diff options
Diffstat (limited to 'libs')
158 files changed, 11766 insertions, 6370 deletions
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 95cfddf..392193b 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -851,6 +851,9 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, tr.target.handle = handle; tr.code = code; tr.flags = binderFlags; + tr.cookie = 0; + tr.sender_pid = 0; + tr.sender_euid = 0; const status_t err = data.errorCheck(); if (err == NO_ERROR) { diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index d57f2c9..a0fc4d0 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -338,7 +338,7 @@ void Parcel::setDataPosition(size_t pos) const status_t Parcel::setDataCapacity(size_t size) { - if (size > mDataSize) return continueWrite(size); + if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } @@ -353,12 +353,12 @@ status_t Parcel::setData(const uint8_t* buffer, size_t len) return err; } -status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) +status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) { const sp<ProcessState> proc(ProcessState::self()); status_t err; - uint8_t *data = parcel->mData; - size_t *objects = parcel->mObjects; + const uint8_t *data = parcel->mData; + const size_t *objects = parcel->mObjects; size_t size = parcel->mObjectsSize; int startPos = mDataPos; int firstIndex = -1, lastIndex = -2; @@ -386,10 +386,12 @@ status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) } int numObjects = lastIndex - firstIndex + 1; - // grow data - err = growData(len); - if (err != NO_ERROR) { - return err; + if ((mDataSize+len) > mDataCapacity) { + // grow data + err = growData(len); + if (err != NO_ERROR) { + return err; + } } // append data @@ -1384,8 +1386,10 @@ status_t Parcel::continueWrite(size_t desired) return NO_MEMORY; } } else { - mDataSize = desired; - LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); + if (mDataSize > desired) { + mDataSize = desired; + LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); + } if (mDataPos > desired) { mDataPos = desired; LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk index 2f16923..b17b3d2 100644 --- a/libs/camera/Android.mk +++ b/libs/camera/Android.mk @@ -13,7 +13,6 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ libhardware \ - libsurfaceflinger_client \ libui \ libgui diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index e288312..5eb48da 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -205,22 +205,6 @@ status_t Camera::startPreview() return c->startPreview(); } -int32_t Camera::getNumberOfVideoBuffers() const -{ - LOGV("getNumberOfVideoBuffers"); - sp <ICamera> c = mCamera; - if (c == 0) return 0; - return c->getNumberOfVideoBuffers(); -} - -sp<IMemory> Camera::getVideoBuffer(int32_t index) const -{ - LOGV("getVideoBuffer: %d", index); - sp <ICamera> c = mCamera; - if (c == 0) return 0; - return c->getVideoBuffer(index); -} - status_t Camera::storeMetaDataInBuffers(bool enabled) { LOGV("storeMetaDataInBuffers: %s", diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 0fd79a4..9392cf2 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -59,6 +59,8 @@ const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode"; const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values"; const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode"; const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values"; +const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas"; +const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas"; const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length"; const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle"; const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle"; @@ -66,6 +68,12 @@ const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensatio const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation"; const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation"; const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step"; +const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock"; +const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported"; +const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock"; +const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported"; +const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas"; +const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas"; const char CameraParameters::KEY_ZOOM[] = "zoom"; const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom"; const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios"; @@ -78,6 +86,7 @@ const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values"; const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video"; const char CameraParameters::TRUE[] = "true"; +const char CameraParameters::FALSE[] = "false"; const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity"; // Values for white balance settings. @@ -137,6 +146,7 @@ const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp"; const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv"; const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p"; const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565"; +const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888"; const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg"; // Values for focus mode settings. diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp index 931b57d..5f6e5ef 100644 --- a/libs/camera/ICamera.cpp +++ b/libs/camera/ICamera.cpp @@ -46,8 +46,6 @@ enum { STOP_RECORDING, RECORDING_ENABLED, RELEASE_RECORDING_FRAME, - GET_NUM_VIDEO_BUFFERS, - GET_VIDEO_BUFFER, STORE_META_DATA_IN_BUFFERS, }; @@ -149,27 +147,6 @@ public: remote()->transact(RELEASE_RECORDING_FRAME, data, &reply); } - int32_t getNumberOfVideoBuffers() const - { - LOGV("getNumberOfVideoBuffers"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(GET_NUM_VIDEO_BUFFERS, data, &reply); - return reply.readInt32(); - } - - sp<IMemory> getVideoBuffer(int32_t index) const - { - LOGV("getVideoBuffer: %d", index); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - data.writeInt32(index); - remote()->transact(GET_VIDEO_BUFFER, data, &reply); - sp<IMemory> mem = interface_cast<IMemory>( - reply.readStrongBinder()); - return mem; - } - status_t storeMetaDataInBuffers(bool enabled) { LOGV("storeMetaDataInBuffers: %s", enabled? "true": "false"); @@ -355,19 +332,6 @@ status_t BnCamera::onTransact( releaseRecordingFrame(mem); return NO_ERROR; } break; - case GET_NUM_VIDEO_BUFFERS: { - LOGV("GET_NUM_VIDEO_BUFFERS"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(getNumberOfVideoBuffers()); - return NO_ERROR; - } break; - case GET_VIDEO_BUFFER: { - LOGV("GET_VIDEO_BUFFER"); - CHECK_INTERFACE(ICamera, data, reply); - int32_t index = data.readInt32(); - reply->writeStrongBinder(getVideoBuffer(index)->asBinder()); - return NO_ERROR; - } break; case STORE_META_DATA_IN_BUFFERS: { LOGV("STORE_META_DATA_IN_BUFFERS"); CHECK_INTERFACE(ICamera, data, reply); diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index d1a6af1..b5737ff 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -10,7 +10,15 @@ LOCAL_SRC_FILES:= \ SensorEventQueue.cpp \ SensorManager.cpp \ SurfaceTexture.cpp \ - SurfaceTextureClient.cpp + SurfaceTextureClient.cpp \ + ISurfaceComposer.cpp \ + ISurface.cpp \ + ISurfaceComposerClient.cpp \ + IGraphicBufferAlloc.cpp \ + LayerState.cpp \ + SharedBufferStack.cpp \ + Surface.cpp \ + SurfaceComposerClient.cpp \ LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -21,7 +29,6 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libEGL \ libGLESv2 \ - libsurfaceflinger_client LOCAL_MODULE:= libgui @@ -31,3 +38,7 @@ ifeq ($(TARGET_SIMULATOR),true) endif include $(BUILD_SHARED_LIBRARY) + +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index e05da72..0cd51da 100644 --- a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -32,7 +32,6 @@ namespace android { enum { CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, }; class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc> @@ -46,8 +45,7 @@ public: virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { Parcel data, reply; - data.writeInterfaceToken( - IGraphicBufferAlloc::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); @@ -58,17 +56,12 @@ public: if (nonNull) { graphicBuffer = new GraphicBuffer(); reply.read(*graphicBuffer); + // reply.readStrongBinder(); + // here we don't even have to read the BufferReference from + // the parcel, it'll die with the parcel. } return graphicBuffer; } - - virtual void freeAllGraphicBuffersExcept(int bufIdx) { - Parcel data, reply; - data.writeInterfaceToken( - IGraphicBufferAlloc::getInterfaceDescriptor()); - data.writeInt32(bufIdx); - remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply); - } }; IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); @@ -80,6 +73,17 @@ status_t BnGraphicBufferAlloc::onTransact( { // codes that don't require permission check + /* BufferReference just keeps a strong reference to a + * GraphicBuffer until it is destroyed (that is, until + * no local or remote process have a reference to it). + */ + class BufferReference : public BBinder { + sp<GraphicBuffer> buffer; + public: + BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { } + }; + + switch(code) { case CREATE_GRAPHIC_BUFFER: { CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); @@ -91,15 +95,16 @@ status_t BnGraphicBufferAlloc::onTransact( reply->writeInt32(result != 0); if (result != 0) { reply->write(*result); + // We add a BufferReference to this parcel to make sure the + // buffer stays alive until the GraphicBuffer object on + // the other side has been created. + // This is needed so that the buffer handle can be + // registered before the buffer is destroyed on implementations + // that do not use file-descriptors to track their buffers. + reply->writeStrongBinder( new BufferReference(result) ); } return NO_ERROR; } break; - case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: { - CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); - int bufIdx = data.readInt32(); - freeAllGraphicBuffersExcept(bufIdx); - return NO_ERROR; - } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/gui/ISurface.cpp index 23b90af..23b90af 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/gui/ISurface.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8951c3f..8951c3f 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 7730eb1..ea38e08 100644 --- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -83,7 +83,6 @@ public: } virtual sp<ISurface> createSurface( surface_data_t* params, - int pid, const String8& name, DisplayID display, uint32_t w, @@ -93,7 +92,6 @@ public: { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeInt32(pid); data.writeString8(name); data.writeInt32(display); data.writeInt32(w); @@ -172,14 +170,13 @@ status_t BnSurfaceComposerClient::onTransact( case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); surface_data_t params; - int32_t pid = data.readInt32(); String8 name = data.readString8(); DisplayID display = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t flags = data.readInt32(); - sp<ISurface> s = createSurface(¶ms, pid, name, display, w, h, + sp<ISurface> s = createSurface(¶ms, name, display, w, h, format, flags); params.writeToParcel(reply); reply->writeStrongBinder(s->asBinder()); diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index d661fd5..16e3780 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -39,6 +39,8 @@ enum { SET_CROP, SET_TRANSFORM, GET_ALLOCATOR, + QUERY, + SET_SYNCHRONOUS_MODE, }; @@ -50,15 +52,10 @@ public: { } - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(bufferIdx); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); sp<GraphicBuffer> buffer; bool nonNull = reply.readInt32(); @@ -79,19 +76,25 @@ public: return err; } - virtual status_t dequeueBuffer(int *buf) { + virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h, + uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); + data.writeInt32(usage); remote()->transact(DEQUEUE_BUFFER, data, &reply); *buf = reply.readInt32(); int result = reply.readInt32(); return result; } - virtual status_t queueBuffer(int buf) { + virtual status_t queueBuffer(int buf, int64_t timestamp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); + data.writeInt64(timestamp); remote()->transact(QUEUE_BUFFER, data, &reply); status_t result = reply.readInt32(); return result; @@ -131,6 +134,27 @@ public: remote()->transact(GET_ALLOCATOR, data, &reply); return reply.readStrongBinder(); } + + virtual int query(int what, int* value) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(what); + remote()->transact(QUERY, data, &reply); + value[0] = reply.readInt32(); + status_t result = reply.readInt32(); + return result; + } + + virtual status_t setSynchronousMode(bool enabled) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInt32(enabled); + remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply); + status_t result = reply.readInt32(); + return result; + } + + }; IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture"); @@ -144,12 +168,7 @@ status_t BnSurfaceTexture::onTransact( case REQUEST_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int bufferIdx = data.readInt32(); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - uint32_t format = data.readInt32(); - uint32_t usage = data.readInt32(); - sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, - usage)); + sp<GraphicBuffer> buffer(requestBuffer(bufferIdx)); reply->writeInt32(buffer != 0); if (buffer != 0) { reply->write(*buffer); @@ -165,8 +184,12 @@ status_t BnSurfaceTexture::onTransact( } break; case DEQUEUE_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + uint32_t format = data.readInt32(); + uint32_t usage = data.readInt32(); int buf; - int result = dequeueBuffer(&buf); + int result = dequeueBuffer(&buf, w, h, format, usage); reply->writeInt32(buf); reply->writeInt32(result); return NO_ERROR; @@ -174,7 +197,8 @@ status_t BnSurfaceTexture::onTransact( case QUEUE_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); - status_t result = queueBuffer(buf); + int64_t timestamp = data.readInt64(); + status_t result = queueBuffer(buf, timestamp); reply->writeInt32(result); return NO_ERROR; } break; @@ -196,7 +220,6 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case SET_TRANSFORM: { - Rect reg; CHECK_INTERFACE(ISurfaceTexture, data, reply); uint32_t transform = data.readInt32(); status_t result = setTransform(transform); @@ -209,6 +232,22 @@ status_t BnSurfaceTexture::onTransact( reply->writeStrongBinder(result); return NO_ERROR; } break; + case QUERY: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + int value; + int what = data.readInt32(); + int res = query(what, &value); + reply->writeInt32(value); + reply->writeInt32(res); + return NO_ERROR; + } break; + case SET_SYNCHRONOUS_MODE: { + CHECK_INTERFACE(ISurfaceTexture, data, reply); + bool enabled = data.readInt32(); + status_t res = setSynchronousMode(enabled); + reply->writeInt32(res); + return NO_ERROR; + } break; } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/surfaceflinger_client/LayerState.cpp b/libs/gui/LayerState.cpp index 01c4c7e..01c4c7e 100644 --- a/libs/surfaceflinger_client/LayerState.cpp +++ b/libs/gui/LayerState.cpp diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index b1f37ff..f9a2c04 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -89,6 +89,14 @@ int32_t Sensor::getMinDelay() const { return mMinDelay; } +nsecs_t Sensor::getMinDelayNs() const { + return getMinDelay() * 1000; +} + +int32_t Sensor::getVersion() const { + return mVersion; +} + size_t Sensor::getFlattenedSize() const { return sizeof(int32_t) + ((mName.length() + 3) & ~3) + diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp index 7505d53..7505d53 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/gui/SharedBufferStack.cpp diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/gui/Surface.cpp index 21d509a..0c5767b 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -502,8 +502,8 @@ status_t Surface::validate(bool inCancelBuffer) const return NO_ERROR; } -sp<ISurface> Surface::getISurface() const { - return mSurface; +sp<IBinder> Surface::asBinder() const { + return mSurface!=0 ? mSurface->asBinder() : 0; } // ---------------------------------------------------------------------------- @@ -513,32 +513,32 @@ int Surface::setSwapInterval(ANativeWindow* window, int interval) { } int Surface::dequeueBuffer(ANativeWindow* window, - android_native_buffer_t** buffer) { + ANativeWindowBuffer** buffer) { Surface* self = getSelf(window); return self->dequeueBuffer(buffer); } int Surface::cancelBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { Surface* self = getSelf(window); return self->cancelBuffer(buffer); } int Surface::lockBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { Surface* self = getSelf(window); return self->lockBuffer(buffer); } int Surface::queueBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { Surface* self = getSelf(window); return self->queueBuffer(buffer); } -int Surface::query(ANativeWindow* window, +int Surface::query(const ANativeWindow* window, int what, int* value) { - Surface* self = getSelf(window); + const Surface* self = getSelf(window); return self->query(what, value); } @@ -570,7 +570,7 @@ bool Surface::needNewBuffer(int bufIdx, return newNeewBuffer; } -int Surface::dequeueBuffer(android_native_buffer_t** buffer) +int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) { status_t err = validate(); if (err != NO_ERROR) @@ -624,7 +624,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return err; } -int Surface::cancelBuffer(android_native_buffer_t* buffer) +int Surface::cancelBuffer(ANativeWindowBuffer* buffer) { status_t err = validate(true); switch (err) { @@ -651,7 +651,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer) } -int Surface::lockBuffer(android_native_buffer_t* buffer) +int Surface::lockBuffer(ANativeWindowBuffer* buffer) { status_t err = validate(); if (err != NO_ERROR) @@ -670,7 +670,7 @@ int Surface::lockBuffer(android_native_buffer_t* buffer) return err; } -int Surface::queueBuffer(android_native_buffer_t* buffer) +int Surface::queueBuffer(ANativeWindowBuffer* buffer) { status_t err = validate(); if (err != NO_ERROR) @@ -697,7 +697,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) return err; } -int Surface::query(int what, int* value) +int Surface::query(int what, int* value) const { switch (what) { case NATIVE_WINDOW_WIDTH: @@ -753,6 +753,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatch_set_buffers_transform( args ); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatch_set_buffers_timestamp( args ); + break; default: res = NAME_NOT_FOUND; break; @@ -792,6 +795,11 @@ int Surface::dispatch_set_buffers_transform(va_list args) { return setBuffersTransform(transform); } +int Surface::dispatch_set_buffers_timestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); @@ -910,6 +918,13 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } +int Surface::setBuffersTimestamp(int64_t timestamp) +{ + // Surface doesn't really have anything meaningful to do with timestamps + // so they'll just be dropped here. + return NO_ERROR; +} + // ---------------------------------------------------------------------------- int Surface::getConnectedApi() const @@ -954,7 +969,7 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - android_native_buffer_t* out; + ANativeWindowBuffer* out; status_t err = dequeueBuffer(&out); LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { @@ -1048,7 +1063,7 @@ int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const if (idx < 0) { // The buffer doesn't have an index set. See if the handle the same as // one of the buffers for which we do know the index. This can happen - // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that + // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that // was dequeued from an ANativeWindow. for (size_t i = 0; i < mBuffers.size(); i++) { if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) { diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d336724..a1ff2c1 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -273,7 +273,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays() } sp<SurfaceControl> SurfaceComposerClient::createSurface( - int pid, DisplayID display, uint32_t w, uint32_t h, @@ -286,12 +285,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( snprintf(buffer, SIZE, "<pid_%d>", getpid()); name.append(buffer); - return SurfaceComposerClient::createSurface(pid, name, display, + return SurfaceComposerClient::createSurface(name, display, w, h, format, flags); } sp<SurfaceControl> SurfaceComposerClient::createSurface( - int pid, const String8& name, DisplayID display, uint32_t w, @@ -302,7 +300,7 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( sp<SurfaceControl> result; if (mStatus == NO_ERROR) { ISurfaceComposerClient::surface_data_t data; - sp<ISurface> surface = mClient->createSurface(&data, pid, name, + sp<ISurface> surface = mClient->createSurface(&data, name, display, w, h, format, flags); if (surface != 0) { result = new SurfaceControl(this, surface, data, w, h, format, flags); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 5c6d71b..ee97dcf 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -27,11 +27,14 @@ #include <gui/SurfaceTexture.h> +#include <hardware/hardware.h> + #include <surfaceflinger/ISurfaceComposer.h> #include <surfaceflinger/SurfaceComposerClient.h> #include <surfaceflinger/IGraphicBufferAlloc.h> #include <utils/Log.h> +#include <utils/String8.h> namespace android { @@ -76,17 +79,23 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); SurfaceTexture::SurfaceTexture(GLuint tex) : - mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), - mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT), - mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) { + mDefaultWidth(1), + mDefaultHeight(1), + mPixelFormat(PIXEL_FORMAT_RGBA_8888), + mBufferCount(MIN_ASYNC_BUFFER_SLOTS), + mClientBufferCount(0), + mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), + mCurrentTexture(INVALID_BUFFER_SLOT), + mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES), + mCurrentTransform(0), + mCurrentTimestamp(0), + mNextTransform(0), + mTexName(tex), + mSynchronousMode(false) { LOGV("SurfaceTexture::SurfaceTexture"); - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; - mSlots[i].mEglDisplay = EGL_NO_DISPLAY; - mSlots[i].mOwnedByClient = false; - } sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); + mNextCrop.makeInvalid(); } SurfaceTexture::~SurfaceTexture() { @@ -94,23 +103,94 @@ SurfaceTexture::~SurfaceTexture() { freeAllBuffers(); } +status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { + if (bufferCount > NUM_BUFFER_SLOTS) + return BAD_VALUE; + + // special-case, nothing to do + if (bufferCount == mBufferCount) + return OK; + + if (!mClientBufferCount && + bufferCount >= mBufferCount) { + // easy, we just have more buffers + mBufferCount = bufferCount; + mServerBufferCount = bufferCount; + mDequeueCondition.signal(); + } else { + // we're here because we're either + // - reducing the number of available buffers + // - or there is a client-buffer-count in effect + + // less than 2 buffers is never allowed + if (bufferCount < 2) + return BAD_VALUE; + + // when there is non client-buffer-count in effect, the client is not + // allowed to dequeue more than one buffer at a time, + // so the next time they dequeue a buffer, we know that they don't + // own one. the actual resizing will happen during the next + // dequeueBuffer. + + mServerBufferCount = bufferCount; + } + return OK; +} + +status_t SurfaceTexture::setBufferCountServer(int bufferCount) { + Mutex::Autolock lock(mMutex); + return setBufferCountServerLocked(bufferCount); +} + status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); + Mutex::Autolock lock(mMutex); + + // Error out if the user has dequeued buffers + for (int i=0 ; i<mBufferCount ; i++) { + if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { + LOGE("setBufferCount: client owns some buffers"); + return -EINVAL; + } + } + + if (bufferCount == 0) { + const int minBufferSlots = mSynchronousMode ? + MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; + mClientBufferCount = 0; + bufferCount = (mServerBufferCount >= minBufferSlots) ? + mServerBufferCount : minBufferSlots; + return setBufferCountServerLocked(bufferCount); + } - if (bufferCount < MIN_BUFFER_SLOTS) { + // We don't allow the client to set a buffer-count less than + // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it. + if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) { return BAD_VALUE; } - Mutex::Autolock lock(mMutex); + // here we're guaranteed that the client doesn't have dequeued buffers + // and will release all of its buffer references. freeAllBuffers(); mBufferCount = bufferCount; + mClientBufferCount = bufferCount; mCurrentTexture = INVALID_BUFFER_SLOT; - mLastQueued = INVALID_BUFFER_SLOT; + mQueue.clear(); + mDequeueCondition.signal(); return OK; } -sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { +status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) +{ + Mutex::Autolock lock(mMutex); + if ((w != mDefaultWidth) || (h != mDefaultHeight)) { + mDefaultWidth = w; + mDefaultHeight = h; + } + return OK; +} + +sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf) { LOGV("SurfaceTexture::requestBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || mBufferCount <= buf) { @@ -118,62 +198,250 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, mBufferCount, buf); return 0; } - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - sp<GraphicBuffer> graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); - if (graphicBuffer == 0) { - LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); - } else { + mSlots[buf].mRequestBufferCalled = true; + return mSlots[buf].mGraphicBuffer; +} + +status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, + uint32_t format, uint32_t usage) { + LOGV("SurfaceTexture::dequeueBuffer"); + + if ((w && !h) || (!w & h)) { + LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + status_t returnFlags(OK); + + int found, foundSync; + int dequeuedCount = 0; + bool tryAgain = true; + while (tryAgain) { + // We need to wait for the FIFO to drain if the number of buffer + // needs to change. + // + // The condition "number of buffer needs to change" is true if + // - the client doesn't care about how many buffers there are + // - AND the actual number of buffer is different from what was + // set in the last setBufferCountServer() + // - OR - + // setBufferCountServer() was set to a value incompatible with + // the synchronization mode (for instance because the sync mode + // changed since) + // + // As long as this condition is true AND the FIFO is not empty, we + // wait on mDequeueCondition. + + int minBufferCountNeeded = mSynchronousMode ? + MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; + + if (!mClientBufferCount && + ((mServerBufferCount != mBufferCount) || + (mServerBufferCount < minBufferCountNeeded))) { + // wait for the FIFO to drain + while (!mQueue.isEmpty()) { + mDequeueCondition.wait(mMutex); + } + minBufferCountNeeded = mSynchronousMode ? + MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; + } + + + if (!mClientBufferCount && + ((mServerBufferCount != mBufferCount) || + (mServerBufferCount < minBufferCountNeeded))) { + // here we're guaranteed that mQueue is empty + freeAllBuffers(); + mBufferCount = mServerBufferCount; + if (mBufferCount < minBufferCountNeeded) + mBufferCount = minBufferCountNeeded; + mCurrentTexture = INVALID_BUFFER_SLOT; + returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; + } + + // look for a free buffer to give to the client + found = INVALID_BUFFER_SLOT; + foundSync = INVALID_BUFFER_SLOT; + dequeuedCount = 0; + for (int i = 0; i < mBufferCount; i++) { + const int state = mSlots[i].mBufferState; + if (state == BufferSlot::DEQUEUED) { + dequeuedCount++; + } + if (state == BufferSlot::FREE || i == mCurrentTexture) { + foundSync = i; + if (i != mCurrentTexture) { + found = i; + break; + } + } + } + + // clients are not allowed to dequeue more than one buffer + // if they didn't set a buffer count. + if (!mClientBufferCount && dequeuedCount) { + return -EINVAL; + } + + // See whether a buffer has been queued since the last setBufferCount so + // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below. + bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; + if (bufferHasBeenQueued) { + // make sure the client is not trying to dequeue more buffers + // than allowed. + const int avail = mBufferCount - (dequeuedCount+1); + if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { + LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)", + MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), + dequeuedCount); + return -EBUSY; + } + } + + // we're in synchronous mode and didn't find a buffer, we need to wait + // for for some buffers to be consumed + tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); + if (tryAgain) { + mDequeueCondition.wait(mMutex); + } + } + + if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { + // foundSync guaranteed to be != INVALID_BUFFER_SLOT + found = foundSync; + } + + if (found == INVALID_BUFFER_SLOT) { + return -EBUSY; + } + + const int buf = found; + *outBuf = found; + + const bool useDefaultSize = !w && !h; + if (useDefaultSize) { + // use the default size + w = mDefaultWidth; + h = mDefaultHeight; + } + + const bool updateFormat = (format != 0); + if (!updateFormat) { + // keep the current (or default) format + format = mPixelFormat; + } + + // buffer is now in DEQUEUED (but can also be current at the same time, + // if we're in synchronous mode) + mSlots[buf].mBufferState = BufferSlot::DEQUEUED; + + const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); + if ((buffer == NULL) || + (uint32_t(buffer->width) != w) || + (uint32_t(buffer->height) != h) || + (uint32_t(buffer->format) != format) || + ((uint32_t(buffer->usage) & usage) != usage)) + { + usage |= GraphicBuffer::USAGE_HW_TEXTURE; + sp<GraphicBuffer> graphicBuffer( + mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); + if (graphicBuffer == 0) { + LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); + return NO_MEMORY; + } + if (updateFormat) { + mPixelFormat = format; + } mSlots[buf].mGraphicBuffer = graphicBuffer; + mSlots[buf].mRequestBufferCalled = false; if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; } - mAllocdBuffers.add(graphicBuffer); + returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } - return graphicBuffer; + return returnFlags; } -status_t SurfaceTexture::dequeueBuffer(int *buf) { - LOGV("SurfaceTexture::dequeueBuffer"); +status_t SurfaceTexture::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); - int found = INVALID_BUFFER_SLOT; - for (int i = 0; i < mBufferCount; i++) { - if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) { - mSlots[i].mOwnedByClient = true; - found = i; - break; + + status_t err = OK; + if (!enabled) { + // going to asynchronous mode, drain the queue + while (mSynchronousMode != enabled && !mQueue.isEmpty()) { + mDequeueCondition.wait(mMutex); } } - if (found == INVALID_BUFFER_SLOT) { - return -EBUSY; + + if (mSynchronousMode != enabled) { + // - if we're going to asynchronous mode, the queue is guaranteed to be + // empty here + // - if the client set the number of buffers, we're guaranteed that + // we have at least 3 (because we don't allow less) + mSynchronousMode = enabled; + mDequeueCondition.signal(); } - *buf = found; - return OK; + return err; } -status_t SurfaceTexture::queueBuffer(int buf) { +status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { LOGV("SurfaceTexture::queueBuffer"); - Mutex::Autolock lock(mMutex); - if (buf < 0 || mBufferCount <= buf) { - LOGE("queueBuffer: slot index out of range [0, %d]: %d", - mBufferCount, buf); - return -EINVAL; - } else if (!mSlots[buf].mOwnedByClient) { - LOGE("queueBuffer: slot %d is not owned by the client", buf); - return -EINVAL; - } else if (mSlots[buf].mGraphicBuffer == 0) { - LOGE("queueBuffer: slot %d was enqueued without requesting a buffer", - buf); - return -EINVAL; - } - mSlots[buf].mOwnedByClient = false; - mLastQueued = buf; - mLastQueuedCrop = mNextCrop; - mLastQueuedTransform = mNextTransform; - if (mFrameAvailableListener != 0) { - mFrameAvailableListener->onFrameAvailable(); + + sp<FrameAvailableListener> listener; + + { // scope for the lock + Mutex::Autolock lock(mMutex); + if (buf < 0 || buf >= mBufferCount) { + LOGE("queueBuffer: slot index out of range [0, %d]: %d", + mBufferCount, buf); + return -EINVAL; + } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { + LOGE("queueBuffer: slot %d is not owned by the client (state=%d)", + buf, mSlots[buf].mBufferState); + return -EINVAL; + } else if (buf == mCurrentTexture) { + LOGE("queueBuffer: slot %d is current!", buf); + return -EINVAL; + } else if (!mSlots[buf].mRequestBufferCalled) { + LOGE("queueBuffer: slot %d was enqueued without requesting a " + "buffer", buf); + return -EINVAL; + } + + if (mQueue.empty()) { + listener = mFrameAvailableListener; + } + + if (mSynchronousMode) { + // in synchronous mode we queue all buffers in a FIFO + mQueue.push_back(buf); + } else { + // in asynchronous mode we only keep the most recent buffer + if (mQueue.empty()) { + mQueue.push_back(buf); + } else { + Fifo::iterator front(mQueue.begin()); + // buffer currently queued is freed + mSlots[*front].mBufferState = BufferSlot::FREE; + // and we record the new buffer index in the queued list + *front = buf; + } + } + + mSlots[buf].mBufferState = BufferSlot::QUEUED; + mSlots[buf].mCrop = mNextCrop; + mSlots[buf].mTransform = mNextTransform; + mSlots[buf].mTimestamp = timestamp; + mDequeueCondition.signal(); + } // scope for the lock + + // call back without lock held + if (listener != 0) { + listener->onFrameAvailable(); } return OK; } @@ -181,15 +449,17 @@ status_t SurfaceTexture::queueBuffer(int buf) { void SurfaceTexture::cancelBuffer(int buf) { LOGV("SurfaceTexture::cancelBuffer"); Mutex::Autolock lock(mMutex); - if (buf < 0 || mBufferCount <= buf) { - LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, - buf); + if (buf < 0 || buf >= mBufferCount) { + LOGE("cancelBuffer: slot index out of range [0, %d]: %d", + mBufferCount, buf); return; - } else if (!mSlots[buf].mOwnedByClient) { - LOGE("cancelBuffer: slot %d is not owned by the client", buf); + } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { + LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", + buf, mSlots[buf].mBufferState); return; } - mSlots[buf].mOwnedByClient = false; + mSlots[buf].mBufferState = BufferSlot::FREE; + mDequeueCondition.signal(); } status_t SurfaceTexture::setCrop(const Rect& crop) { @@ -208,50 +478,125 @@ status_t SurfaceTexture::setTransform(uint32_t transform) { status_t SurfaceTexture::updateTexImage() { LOGV("SurfaceTexture::updateTexImage"); + Mutex::Autolock lock(mMutex); - // We always bind the texture even if we don't update its contents. - glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); + int buf = mCurrentTexture; + if (!mQueue.empty()) { + // in asynchronous mode the list is guaranteed to be one buffer deep, + // while in synchronous mode we use the oldest buffer + Fifo::iterator front(mQueue.begin()); + buf = *front; + mQueue.erase(front); + if (mQueue.isEmpty()) { + mDequeueCondition.signal(); + } + } - // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT, + // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT, // so this check will fail until a buffer gets queued. - if (mCurrentTexture != mLastQueued) { + if (mCurrentTexture != buf) { // Update the GL texture object. - EGLImageKHR image = mSlots[mLastQueued].mEglImage; + EGLImageKHR image = mSlots[buf].mEglImage; if (image == EGL_NO_IMAGE_KHR) { EGLDisplay dpy = eglGetCurrentDisplay(); - sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer; - image = createImage(dpy, graphicBuffer); - mSlots[mLastQueued].mEglImage = image; - mSlots[mLastQueued].mEglDisplay = dpy; + image = createImage(dpy, mSlots[buf].mGraphicBuffer); + mSlots[buf].mEglImage = image; + mSlots[buf].mEglDisplay = dpy; + if (image == EGL_NO_IMAGE_KHR) { + // NOTE: if dpy was invalid, createImage() is guaranteed to + // fail. so we'd end up here. + return -EINVAL; + } } GLint error; while ((error = glGetError()) != GL_NO_ERROR) { - LOGE("GL error cleared before updating SurfaceTexture: %#04x", error); + LOGW("updateTexImage: clearing GL error: %#04x", error); + } + + GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format); + if (target != mCurrentTextureTarget) { + glDeleteTextures(1, &mTexName); } - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); + glBindTexture(target, mTexName); + glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image); + bool failed = false; while ((error = glGetError()) != GL_NO_ERROR) { LOGE("error binding external texture image %p (slot %d): %#04x", - image, mLastQueued, error); + image, buf, error); failed = true; } if (failed) { return -EINVAL; } + if (mCurrentTexture != INVALID_BUFFER_SLOT) { + // the current buffer becomes FREE if it was still in the queued + // state. If it has already been given to the client + // (synchronous mode), then it stays in DEQUEUED state. + if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) + mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE; + } + // Update the SurfaceTexture state. - mCurrentTexture = mLastQueued; - mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; - mCurrentCrop = mLastQueuedCrop; - mCurrentTransform = mLastQueuedTransform; + mCurrentTexture = buf; + mCurrentTextureTarget = target; + mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; + mCurrentCrop = mSlots[buf].mCrop; + mCurrentTransform = mSlots[buf].mTransform; + mCurrentTimestamp = mSlots[buf].mTimestamp; + mDequeueCondition.signal(); + } else { + // We always bind the texture even if we don't update its contents. + glBindTexture(mCurrentTextureTarget, mTexName); } return OK; } +size_t SurfaceTexture::getQueuedCount() const { + Mutex::Autolock lock(mMutex); + return mQueue.size(); +} + +bool SurfaceTexture::isExternalFormat(uint32_t format) +{ + switch (format) { + // supported YUV formats + case HAL_PIXEL_FORMAT_YV12: + // Legacy/deprecated YUV formats + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + return true; + } + + // Any OEM format needs to be considered + if (format>=0x100 && format<=0x1FF) + return true; + + return false; +} + +GLenum SurfaceTexture::getTextureTarget(uint32_t format) +{ + GLenum target = GL_TEXTURE_2D; +#if defined(GL_OES_EGL_image_external) + if (isExternalFormat(format)) { + target = GL_TEXTURE_EXTERNAL_OES; + } +#endif + return target; +} + +GLenum SurfaceTexture::getCurrentTextureTarget() const { + Mutex::Autolock lock(mMutex); + return mCurrentTextureTarget; +} + void SurfaceTexture::getTransformMatrix(float mtx[16]) { - LOGV("SurfaceTexture::updateTexImage"); + LOGV("SurfaceTexture::getTransformMatrix"); Mutex::Autolock lock(mMutex); float xform[16]; @@ -304,10 +649,10 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { } else { tx = 0.0f; } - if (mCurrentCrop.right < buf->getWidth()) { + if (mCurrentCrop.right < int32_t(buf->getWidth())) { xshrink++; } - if (mCurrentCrop.bottom < buf->getHeight()) { + if (mCurrentCrop.bottom < int32_t(buf->getHeight())) { ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) / float(buf->getHeight()); yshrink++; @@ -342,6 +687,12 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); } +nsecs_t SurfaceTexture::getTimestamp() { + LOGV("SurfaceTexture::getTimestamp"); + Mutex::Autolock lock(mMutex); + return mCurrentTimestamp; +} + void SurfaceTexture::setFrameAvailableListener( const sp<FrameAvailableListener>& l) { LOGV("SurfaceTexture::setFrameAvailableListener"); @@ -357,26 +708,13 @@ sp<IBinder> SurfaceTexture::getAllocator() { void SurfaceTexture::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].mGraphicBuffer = 0; - mSlots[i].mOwnedByClient = false; + mSlots[i].mBufferState = BufferSlot::FREE; if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; mSlots[i].mEglDisplay = EGL_NO_DISPLAY; } } - - int exceptBuf = -1; - for (size_t i = 0; i < mAllocdBuffers.size(); i++) { - if (mAllocdBuffers[i] == mCurrentTextureBuf) { - exceptBuf = i; - break; - } - } - mAllocdBuffers.clear(); - if (exceptBuf >= 0) { - mAllocdBuffers.add(mCurrentTextureBuf); - } - mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf); } EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, @@ -388,16 +726,119 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, }; EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { + if (image == EGL_NO_IMAGE_KHR) { + EGLint error = eglGetError(); LOGE("error creating EGLImage: %#x", error); - } else if (image == EGL_NO_IMAGE_KHR) { - LOGE("no error reported, but no image was returned by " - "eglCreateImageKHR"); } return image; } +sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const { + Mutex::Autolock lock(mMutex); + return mCurrentTextureBuf; +} + +Rect SurfaceTexture::getCurrentCrop() const { + Mutex::Autolock lock(mMutex); + return mCurrentCrop; +} + +uint32_t SurfaceTexture::getCurrentTransform() const { + Mutex::Autolock lock(mMutex); + return mCurrentTransform; +} + +int SurfaceTexture::query(int what, int* outValue) +{ + Mutex::Autolock lock(mMutex); + int value; + switch (what) { + case NATIVE_WINDOW_WIDTH: + value = mDefaultWidth; + if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0) + value = mCurrentTextureBuf->width; + break; + case NATIVE_WINDOW_HEIGHT: + value = mDefaultHeight; + if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0) + value = mCurrentTextureBuf->height; + break; + case NATIVE_WINDOW_FORMAT: + value = mPixelFormat; + break; + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + value = mSynchronousMode ? + (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS; + break; + default: + return BAD_VALUE; + } + outValue[0] = value; + return NO_ERROR; +} + +void SurfaceTexture::dump(String8& result) const +{ + char buffer[1024]; + dump(result, "", buffer, 1024); +} + +void SurfaceTexture::dump(String8& result, const char* prefix, + char* buffer, size_t SIZE) const +{ + Mutex::Autolock _l(mMutex); + snprintf(buffer, SIZE, + "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " + "mPixelFormat=%d, mTexName=%d\n", + prefix, mBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, + mPixelFormat, mTexName); + result.append(buffer); + + String8 fifo; + int fifoSize = 0; + Fifo::const_iterator i(mQueue.begin()); + while (i != mQueue.end()) { + snprintf(buffer, SIZE, "%02d ", *i++); + fifoSize++; + fifo.append(buffer); + } + + snprintf(buffer, SIZE, + "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n" + "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n" + , + prefix, mCurrentCrop.left, + mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, + mCurrentTransform, mCurrentTexture, mCurrentTextureTarget, + prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom, + mCurrentTransform, fifoSize, fifo.string() + ); + result.append(buffer); + + struct { + const char * operator()(int state) const { + switch (state) { + case BufferSlot::DEQUEUED: return "DEQUEUED"; + case BufferSlot::QUEUED: return "QUEUED"; + case BufferSlot::FREE: return "FREE"; + default: return "Unknown"; + } + } + } stateName; + + for (int i=0 ; i<mBufferCount ; i++) { + const BufferSlot& slot(mSlots[i]); + snprintf(buffer, SIZE, + "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, " + "timestamp=%lld\n", + prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState), + slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom, + slot.mTransform, slot.mTimestamp + ); + result.append(buffer); + } +} + static void mtxMul(float out[16], const float a[16], const float b[16]) { out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 7f1d9cb..c20fcf2 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -25,8 +25,11 @@ namespace android { SurfaceTextureClient::SurfaceTextureClient( const sp<ISurfaceTexture>& surfaceTexture): - mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1), - mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() { + mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0), + mReqHeight(0), mReqFormat(0), mReqUsage(0), + mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0), + mQueryWidth(0), mQueryHeight(0), mQueryFormat(0), + mMutex() { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; @@ -36,6 +39,9 @@ SurfaceTextureClient::SurfaceTextureClient( ANativeWindow::query = query; ANativeWindow::perform = perform; + const_cast<int&>(ANativeWindow::minSwapInterval) = 0; + const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; + // Get a reference to the allocator. mAllocator = mSurfaceTexture->getAllocator(); } @@ -50,31 +56,32 @@ int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) { } int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window, - android_native_buffer_t** buffer) { + ANativeWindowBuffer** buffer) { SurfaceTextureClient* c = getSelf(window); return c->dequeueBuffer(buffer); } int SurfaceTextureClient::cancelBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); return c->cancelBuffer(buffer); } int SurfaceTextureClient::lockBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); return c->lockBuffer(buffer); } int SurfaceTextureClient::queueBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) { + ANativeWindowBuffer* buffer) { SurfaceTextureClient* c = getSelf(window); return c->queueBuffer(buffer); } -int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) { - SurfaceTextureClient* c = getSelf(window); +int SurfaceTextureClient::query(const ANativeWindow* window, + int what, int* value) { + const SurfaceTextureClient* c = getSelf(window); return c->query(what, value); } @@ -86,29 +93,48 @@ int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) { } int SurfaceTextureClient::setSwapInterval(int interval) { - return INVALID_OPERATION; + // EGL specification states: + // interval is silently clamped to minimum and maximum implementation + // dependent values before being stored. + // Although we don't have to, we apply the same logic here. + + if (interval < minSwapInterval) + interval = minSwapInterval; + + if (interval > maxSwapInterval) + interval = maxSwapInterval; + + status_t res = mSurfaceTexture->setSynchronousMode(interval ? true : false); + + return res; } int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { LOGV("SurfaceTextureClient::dequeueBuffer"); Mutex::Autolock lock(mMutex); int buf = -1; - status_t err = mSurfaceTexture->dequeueBuffer(&buf); - if (err < 0) { - LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer failed: %d", err); - return err; + status_t result = mSurfaceTexture->dequeueBuffer(&buf, mReqWidth, mReqHeight, + mReqFormat, mReqUsage); + if (result < 0) { + LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)" + "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, + result); + return result; } sp<GraphicBuffer>& gbuf(mSlots[buf]); - if (gbuf == 0 || gbuf->getWidth() != mReqWidth || - gbuf->getHeight() != mReqHeight || - uint32_t(gbuf->getPixelFormat()) != mReqFormat || - (gbuf->getUsage() & mReqUsage) != mReqUsage) { - gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight, - mReqFormat, mReqUsage); + if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) { + freeAllBuffers(); + } + + if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { + gbuf = mSurfaceTexture->requestBuffer(buf); if (gbuf == 0) { LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed"); return NO_MEMORY; } + mQueryWidth = gbuf->width; + mQueryHeight = gbuf->height; + mQueryFormat = gbuf->format; } *buffer = gbuf.get(); return OK; @@ -135,40 +161,36 @@ int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) { int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); + int64_t timestamp; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); + } else { + timestamp = mTimestamp; + } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i]->handle == buffer->handle) { - return mSurfaceTexture->queueBuffer(i); + return mSurfaceTexture->queueBuffer(i, timestamp); } } LOGE("queueBuffer: unknown buffer queued"); return BAD_VALUE; } -int SurfaceTextureClient::query(int what, int* value) { +int SurfaceTextureClient::query(int what, int* value) const { LOGV("SurfaceTextureClient::query"); - Mutex::Autolock lock(mMutex); switch (what) { - case NATIVE_WINDOW_WIDTH: - case NATIVE_WINDOW_HEIGHT: - // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't - // override the size? - *value = 0; - return NO_ERROR; - case NATIVE_WINDOW_FORMAT: - *value = DEFAULT_FORMAT; - return NO_ERROR; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - *value = MIN_UNDEQUEUED_BUFFERS; - return NO_ERROR; case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: - // SurfaceTextureClient currently never queues frames to SurfaceFlinger. + // TODO: this is not needed anymore *value = 0; return NO_ERROR; case NATIVE_WINDOW_CONCRETE_TYPE: + // TODO: this is not needed anymore *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; return NO_ERROR; } - return BAD_VALUE; + return mSurfaceTexture->query(what, value); } int SurfaceTextureClient::perform(int operation, va_list args) @@ -196,6 +218,9 @@ int SurfaceTextureClient::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatchSetBuffersTransform(args); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatchSetBuffersTimestamp(args); + break; default: res = NAME_NOT_FOUND; break; @@ -240,18 +265,56 @@ int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { return setBuffersTransform(transform); } +int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + int SurfaceTextureClient::connect(int api) { LOGV("SurfaceTextureClient::connect"); - // XXX: Implement this! - return INVALID_OPERATION; + Mutex::Autolock lock(mMutex); + int err = NO_ERROR; + switch (api) { + case NATIVE_WINDOW_API_EGL: + if (mConnectedApi) { + err = -EINVAL; + } else { + mConnectedApi = api; + } + break; + default: + err = -EINVAL; + break; + } + return err; } int SurfaceTextureClient::disconnect(int api) { LOGV("SurfaceTextureClient::disconnect"); - // XXX: Implement this! - return INVALID_OPERATION; + Mutex::Autolock lock(mMutex); + int err = NO_ERROR; + switch (api) { + case NATIVE_WINDOW_API_EGL: + if (mConnectedApi == api) { + mConnectedApi = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + break; + } + return err; } +int SurfaceTextureClient::getConnectedApi() const +{ + Mutex::Autolock lock(mMutex); + return mConnectedApi; +} + + int SurfaceTextureClient::setUsage(uint32_t reqUsage) { LOGV("SurfaceTextureClient::setUsage"); @@ -323,6 +386,14 @@ int SurfaceTextureClient::setBuffersTransform(int transform) return err; } +int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp) +{ + LOGV("SurfaceTextureClient::setBuffersTimestamp"); + Mutex::Autolock lock(mMutex); + mTimestamp = timestamp; + return NO_ERROR; +} + void SurfaceTextureClient::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i] = 0; diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 7516299..8d3a9b5 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE := SurfaceTexture_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ + Surface_test.cpp \ SurfaceTextureClient_test.cpp \ SurfaceTexture_test.cpp \ @@ -20,7 +21,6 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libgui \ libstlport \ - libsurfaceflinger_client \ libui \ libutils \ @@ -36,9 +36,6 @@ LOCAL_C_INCLUDES := \ include $(BUILD_EXECUTABLE) -# Build the manual test programs. -include $(call all-subdir-makefiles) - endif # Include subdirectory makefiles diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 94b05bc..2f704c8 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -17,23 +17,78 @@ #include <EGL/egl.h> #include <gtest/gtest.h> #include <gui/SurfaceTextureClient.h> +#include <utils/threads.h> namespace android { class SurfaceTextureClientTest : public ::testing::Test { protected: + SurfaceTextureClientTest(): + mEglDisplay(EGL_NO_DISPLAY), + mEglSurface(EGL_NO_SURFACE), + mEglContext(EGL_NO_CONTEXT) { + } + virtual void SetUp() { mST = new SurfaceTexture(123); mSTC = new SurfaceTextureClient(mST); + + // We need a valid GL context so we can test updateTexImage() + // This initializes EGL and create a dummy GL context with a + // pbuffer render target. + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay); + + EGLint majorVersion, minorVersion; + EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EGLConfig myConfig; + EGLint numConfigs = 0; + EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), + &myConfig, 1, &numConfigs)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EGLint pbufferAttribs[] = { + EGL_WIDTH, 16, + EGL_HEIGHT, 16, + EGL_NONE }; + mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig, pbufferAttribs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, mEglSurface); + + mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_CONTEXT, mEglContext); + + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); } virtual void TearDown() { mST.clear(); mSTC.clear(); + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(mEglDisplay, mEglContext); + eglDestroySurface(mEglDisplay, mEglSurface); + eglTerminate(mEglDisplay); + } + + virtual EGLint const* getConfigAttribs() { + static EGLint sDefaultConfigAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + + return sDefaultConfigAttribs; } sp<SurfaceTexture> mST; sp<SurfaceTextureClient> mSTC; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLContext mEglContext; }; TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) { @@ -64,7 +119,7 @@ TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) { ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(anw.get(), &buf, NULL)); } -TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) { +TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) { sp<ANativeWindow> anw(mSTC); EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -94,10 +149,369 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) { EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, anw.get(), NULL); - ASSERT_EQ(EGL_NO_SURFACE, eglSurface); - ASSERT_EQ(EGL_BAD_NATIVE_WINDOW, eglGetError()); + EXPECT_NE(EGL_NO_SURFACE, eglSurface); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); eglTerminate(dpy); } +TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { + sp<ANativeWindow> anw(mSTC); + + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, 0, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, -1, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, -1)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, -1, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, 8, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 8, 0, 0)); +} + +TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { + sp<ANativeWindow> anw(mSTC); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + ANativeWindowBuffer* buf; + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + ANativeWindowBuffer* buf[2]; + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(16, buf[0]->width); + EXPECT_EQ(16, buf[1]->width); + EXPECT_EQ(8, buf[0]->height); + EXPECT_EQ(8, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + ANativeWindowBuffer* buf[2]; + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4)); + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(16, buf[0]->width); + EXPECT_EQ(16, buf[1]->width); + EXPECT_EQ(8, buf[0]->height); + EXPECT_EQ(8, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 12, 24, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(12, buf[0]->width); + EXPECT_EQ(12, buf[1]->width); + EXPECT_EQ(24, buf[0]->height); + EXPECT_EQ(24, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(false)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4)); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(OK, st->updateTexImage()); + + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3)); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(OK, st->updateTexImage()); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_NE(buf[1], buf[2]); + EXPECT_NE(buf[2], buf[0]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_NE(buf[1], buf[2]); + EXPECT_NE(buf[2], buf[0]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3)); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + EXPECT_NE(buf[1], buf[2]); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2])); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]); +} + +// XXX: We currently have no hardware that properly handles dequeuing the +// buffer that is currently bound to the texture. +TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + android_native_buffer_t* firstBuf; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &firstBuf)); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), firstBuf)); + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), firstBuf); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_NE(buf[1], buf[2]); + EXPECT_NE(buf[2], buf[0]); + EXPECT_EQ(firstBuf, buf[2]); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3)); + + // We should be able to dequeue all the buffers before we've queued any. + EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + + EXPECT_EQ(OK, st->updateTexImage()); + EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]); + + EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + + // Once we've queued a buffer, however we should not be able to dequeue more + // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case. + EXPECT_EQ(-EBUSY, anw->dequeueBuffer(anw.get(), &buf[1])); + + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2])); +} + +// XXX: This is not expected to pass until the synchronization hacks are removed +// from the SurfaceTexture class. +TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + + class MyThread : public Thread { + sp<SurfaceTexture> st; + EGLContext ctx; + EGLSurface sur; + EGLDisplay dpy; + bool mBufferRetired; + Mutex mLock; + virtual bool threadLoop() { + eglMakeCurrent(dpy, sur, sur, ctx); + usleep(20000); + Mutex::Autolock _l(mLock); + st->updateTexImage(); + mBufferRetired = true; + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + return false; + } + public: + MyThread(const sp<SurfaceTexture>& st) + : st(st), mBufferRetired(false) { + ctx = eglGetCurrentContext(); + sur = eglGetCurrentSurface(EGL_DRAW); + dpy = eglGetCurrentDisplay(); + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + ~MyThread() { + eglMakeCurrent(dpy, sur, sur, ctx); + } + void bufferDequeued() { + Mutex::Autolock _l(mLock); + EXPECT_EQ(true, mBufferRetired); + } + }; + + android_native_buffer_t* buf[3]; + ASSERT_EQ(OK, st->setSynchronousMode(true)); + ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3)); + // dequeue/queue/update so we have a current buffer + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + st->updateTexImage(); + + MyThread* thread = new MyThread(st); + sp<Thread> threadBase(thread); + + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1])); + thread->run(); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2])); + ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2])); + thread->bufferDequeued(); + thread->requestExitAndWait(); +} + } diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index 4184463..8747ba5 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -76,7 +76,7 @@ protected: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - mSurfaceControl = mComposerClient->createSurface(getpid(), + mSurfaceControl = mComposerClient->createSurface( String8("Test Surface"), 0, getSurfaceWidth(), getSurfaceHeight(), PIXEL_FORMAT_RGB_888, 0); @@ -476,7 +476,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); - android_native_buffer_t* anb; + ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); @@ -524,7 +524,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) { ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); - android_native_buffer_t* anb; + ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); @@ -583,7 +583,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); - android_native_buffer_t* anb; + ANativeWindowBuffer* anb; ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); ASSERT_TRUE(anb != NULL); diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index fd07479..35c8640 100644 --- a/libs/surfaceflinger_client/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -30,7 +30,7 @@ protected: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - mSurfaceControl = mComposerClient->createSurface(getpid(), + mSurfaceControl = mComposerClient->createSurface( String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0); ASSERT_TRUE(mSurfaceControl != NULL); @@ -93,7 +93,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), GRALLOC_USAGE_PROTECTED)); ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); - android_native_buffer_t* buf = 0; + ANativeWindowBuffer* buf = 0; for (int i = 0; i < 4; i++) { // Loop to make sure SurfaceFlinger has retired a protected buffer. ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index f4a0161..a98e4cd 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -9,6 +9,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) FontRenderer.cpp \ GammaFontRenderer.cpp \ Caches.cpp \ + DisplayListLogBuffer.cpp \ DisplayListRenderer.cpp \ FboCache.cpp \ GradientCache.cpp \ @@ -42,7 +43,6 @@ ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui LOCAL_MODULE := libhwui LOCAL_MODULE_TAGS := optional - LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 4f5edd5..b0d8cf9 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "OpenGLRenderer" #include <utils/Log.h> +#include <utils/String8.h> #include "Caches.h" #include "Properties.h" @@ -69,30 +70,43 @@ Caches::~Caches() { /////////////////////////////////////////////////////////////////////////////// void Caches::dumpMemoryUsage() { - LOGD("Current memory usage / total memory usage (bytes):"); - LOGD(" TextureCache %8d / %8d", textureCache.getSize(), textureCache.getMaxSize()); - LOGD(" LayerCache %8d / %8d", layerCache.getSize(), layerCache.getMaxSize()); - LOGD(" GradientCache %8d / %8d", gradientCache.getSize(), gradientCache.getMaxSize()); - LOGD(" PathCache %8d / %8d", pathCache.getSize(), pathCache.getMaxSize()); - LOGD(" CircleShapeCache %8d / %8d", + String8 stringLog; + dumpMemoryUsage(stringLog); + LOGD("%s", stringLog.string()); + delete stringLog; +} + +void Caches::dumpMemoryUsage(String8 &log) { + log.appendFormat("Current memory usage / total memory usage (bytes):\n"); + log.appendFormat(" TextureCache %8d / %8d\n", + textureCache.getSize(), textureCache.getMaxSize()); + log.appendFormat(" LayerCache %8d / %8d\n", + layerCache.getSize(), layerCache.getMaxSize()); + log.appendFormat(" GradientCache %8d / %8d\n", + gradientCache.getSize(), gradientCache.getMaxSize()); + log.appendFormat(" PathCache %8d / %8d\n", + pathCache.getSize(), pathCache.getMaxSize()); + log.appendFormat(" CircleShapeCache %8d / %8d\n", circleShapeCache.getSize(), circleShapeCache.getMaxSize()); - LOGD(" OvalShapeCache %8d / %8d", + log.appendFormat(" OvalShapeCache %8d / %8d\n", ovalShapeCache.getSize(), ovalShapeCache.getMaxSize()); - LOGD(" RoundRectShapeCache %8d / %8d", + log.appendFormat(" RoundRectShapeCache %8d / %8d\n", roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize()); - LOGD(" RectShapeCache %8d / %8d", + log.appendFormat(" RectShapeCache %8d / %8d\n", rectShapeCache.getSize(), rectShapeCache.getMaxSize()); - LOGD(" ArcShapeCache %8d / %8d", + log.appendFormat(" ArcShapeCache %8d / %8d\n", arcShapeCache.getSize(), arcShapeCache.getMaxSize()); - LOGD(" TextDropShadowCache %8d / %8d", dropShadowCache.getSize(), + log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(), dropShadowCache.getMaxSize()); for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { const uint32_t size = fontRenderer.getFontRendererSize(i); - LOGD(" FontRenderer %d %8d / %8d", i, size, size); + log.appendFormat(" FontRenderer %d %8d / %8d\n", i, size, size); } - LOGD("Other:"); - LOGD(" FboCache %8d / %8d", fboCache.getSize(), fboCache.getMaxSize()); - LOGD(" PatchCache %8d / %8d", patchCache.getSize(), patchCache.getMaxSize()); + log.appendFormat("Other:\n"); + log.appendFormat(" FboCache %8d / %8d\n", + fboCache.getSize(), fboCache.getMaxSize()); + log.appendFormat(" PatchCache %8d / %8d\n", + patchCache.getSize(), patchCache.getMaxSize()); uint32_t total = 0; total += textureCache.getSize(); @@ -109,9 +123,8 @@ void Caches::dumpMemoryUsage() { total += fontRenderer.getFontRendererSize(i); } - LOGD("Total memory usage:"); - LOGD(" %d bytes, %.2f MB", total, total / 1024.0f / 1024.0f); - LOGD("\n"); + log.appendFormat("Total memory usage:\n"); + log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 0a9335f..596781e 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -60,7 +60,12 @@ static const TextureVertex gMeshVertices[] = { FV(1.0f, 1.0f, 1.0f, 1.0f) }; static const GLsizei gMeshStride = sizeof(TextureVertex); +static const GLsizei gVertexStride = sizeof(Vertex); +static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex); +static const GLsizei gAAVertexStride = sizeof(AAVertex); static const GLsizei gMeshTextureOffset = 2 * sizeof(float); +static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float); +static const GLsizei gVertexAALengthOffset = 3 * sizeof(float); static const GLsizei gMeshCount = 4; /////////////////////////////////////////////////////////////////////////////// @@ -140,6 +145,7 @@ public: * Displays the memory usage of each cache and the total sum. */ void dumpMemoryUsage(); + void dumpMemoryUsage(String8& log); bool blend; GLenum lastSrcMode; diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index 14471bc..2cdc8c3 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -26,7 +26,7 @@ // Turn on to enable memory usage summary on each frame #define DEBUG_MEMORY_USAGE 0 -// Turn on to enable layers debugging when renderered as regions +// Turn on to enable layers debugging when rendered as regions #define DEBUG_LAYERS_AS_REGIONS 0 // Turn on to display debug info about vertex/fragment shaders @@ -35,8 +35,10 @@ // Turn on to display info about layers #define DEBUG_LAYERS 0 -// Turn on to display debug infor about 9patch objects +// Turn on to display debug info about 9patch objects #define DEBUG_PATCHES 0 +// Turn on to "explode" 9patch objects +#define DEBUG_EXPLODE_PATCHES 0 // Turn on to display vertex and tex coords data about 9patch objects // This flag requires DEBUG_PATCHES to be turned on #define DEBUG_PATCHES_VERTICES 0 diff --git a/libs/hwui/DisplayListLogBuffer.cpp b/libs/hwui/DisplayListLogBuffer.cpp new file mode 100644 index 0000000..f204644 --- /dev/null +++ b/libs/hwui/DisplayListLogBuffer.cpp @@ -0,0 +1,124 @@ +/* + * 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 "DisplayListLogBuffer.h" + +// BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure +// that mStart always points at the next command, not just the next item +#define COMMAND_SIZE 2 +#define NUM_COMMANDS 50 +#define BUFFER_SIZE ((NUM_COMMANDS * COMMAND_SIZE) + 1) + +/** + * DisplayListLogBuffer is a utility class which logs the most recent display + * list operations in a circular buffer. The log is process-wide, because we + * only care about the most recent operations, not the operations on a per-window + * basis for a given activity. The purpose of the log is to provide more debugging + * information in a bug report, by telling us not just where a process hung (which + * generally is just reported as a stack trace at the Java level) or crashed, but + * also what happened immediately before that hang or crash. This may help track down + * problems in the native rendering code or driver interaction related to the display + * list operations that led up to the hang or crash. + * + * The log is implemented as a circular buffer for both space and performance + * reasons - we only care about the last several operations to give us context + * leading up to the problem, and we don't want to constantly copy data around or do + * additional mallocs to keep the most recent operations logged. Only numbers are + * logged to make the operation fast. If and when the log is output, we process this + * data into meaningful strings. + * + * There is an assumption about the format of the command (currently 2 ints: the + * opcode and the nesting level). If the type of information logged changes (for example, + * we may want to save a timestamp), then the size of the buffer and the way the + * information is recorded in writeCommand() should change to suit. + */ + +namespace android { + +#ifdef USE_OPENGL_RENDERER +using namespace uirenderer; +ANDROID_SINGLETON_STATIC_INSTANCE(DisplayListLogBuffer); +#endif + +namespace uirenderer { + + +DisplayListLogBuffer::DisplayListLogBuffer() { + mBufferFirst = (int*) malloc(BUFFER_SIZE * sizeof(int)); + mStart = mBufferFirst; + mBufferLast = mBufferFirst + BUFFER_SIZE - 1; + mEnd = mStart; +} + +DisplayListLogBuffer::~DisplayListLogBuffer() { + free(mBufferFirst); +} + +/** + * Called from DisplayListRenderer to output the current buffer into the + * specified FILE. This only happens in a dumpsys/bugreport operation. + */ +void DisplayListLogBuffer::outputCommands(FILE *file, const char* opNames[]) +{ + int *tmpBufferPtr = mStart; + while (true) { + if (tmpBufferPtr == mEnd) { + break; + } + int level = *tmpBufferPtr++; + if (tmpBufferPtr > mBufferLast) { + tmpBufferPtr = mBufferFirst; + } + int op = *tmpBufferPtr++; + if (tmpBufferPtr > mBufferLast) { + tmpBufferPtr = mBufferFirst; + } + uint32_t count = (level + 1) * 2; + char indent[count + 1]; + for (uint32_t i = 0; i < count; i++) { + indent[i] = ' '; + } + indent[count] = '\0'; + fprintf(file, "%s%s\n", indent, opNames[op]); + } +} + +void DisplayListLogBuffer::writeCommand(int level, int op) { + writeInt(level); + writeInt(op); +} + +/** + * Store the given value in the buffer and increment/wrap the mEnd + * and mStart values as appropriate. + */ +void DisplayListLogBuffer::writeInt(int value) { + *((int*)mEnd) = value; + if (mEnd == mBufferLast) { + mEnd = mBufferFirst; + } else { + mEnd++; + } + if (mEnd == mStart) { + mStart++; + if (mStart > mBufferLast) { + mStart = mBufferFirst; + } + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h new file mode 100644 index 0000000..bf16f29 --- /dev/null +++ b/libs/hwui/DisplayListLogBuffer.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H +#define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H + +#include <utils/Singleton.h> +#include <stdio.h> + +namespace android { +namespace uirenderer { + +class DisplayListLogBuffer: public Singleton<DisplayListLogBuffer> { + DisplayListLogBuffer(); + ~DisplayListLogBuffer(); + + friend class Singleton<DisplayListLogBuffer>; + +public: + void writeCommand(int level, int op); + void writeInt(int value); + void outputCommands(FILE *file, const char* opNames[]); + + bool isEmpty() { + return (mStart == mEnd); + } + +private: + int *mBufferFirst; // where the memory starts + int* mStart; // where the current command stream starts + int* mEnd; // where the current commands end + int* mBufferLast; // where the buffer memory ends + +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 868290b..afab26a 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -16,11 +16,16 @@ #define LOG_TAG "OpenGLRenderer" + +#include "DisplayListLogBuffer.h" #include "DisplayListRenderer.h" +#include <utils/String8.h> +#include "Caches.h" namespace android { namespace uirenderer { + /////////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////////// @@ -53,6 +58,7 @@ const char* DisplayList::OP_NAMES[] = { "DrawArc", "DrawPath", "DrawLines", + "DrawPoints", "DrawText", "ResetShader", "SetupShader", @@ -63,6 +69,20 @@ const char* DisplayList::OP_NAMES[] = { "DrawGLFunction" }; +void DisplayList::outputLogBuffer(int fd) { + DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); + if (logBuffer.isEmpty()) { + return; + } + String8 cachesLog; + Caches::getInstance().dumpMemoryUsage(cachesLog); + FILE *file = fdopen(fd, "a"); + fprintf(file, "\nCaches:\n%s", cachesLog.string()); + fprintf(file, "\nRecent DisplayList operations\n"); + logBuffer.outputCommands(file, OP_NAMES); + fflush(file); +} + DisplayList::DisplayList(const DisplayListRenderer& recorder) { initFromDisplayListRenderer(recorder); } @@ -92,13 +112,11 @@ void DisplayList::clearResources() { mPaints.clear(); for (size_t i = 0; i < mPaths.size(); i++) { - delete mPaths.itemAt(i); + SkPath* path = mPaths.itemAt(i); + caches.pathCache.remove(path); + delete path; } mPaths.clear(); - for (size_t i = 0; i < mOriginalPaths.size(); i++) { - caches.resourceCache.decrementRefcount(mOriginalPaths.itemAt(i)); - } - mOriginalPaths.clear(); for (size_t i = 0; i < mMatrices.size(); i++) { delete mMatrices.itemAt(i); @@ -150,13 +168,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde mPaths.add(paths.itemAt(i)); } - const Vector<SkPath*> &originalPaths = recorder.getOriginalPaths(); - for (size_t i = 0; i < originalPaths.size(); i++) { - SkPath* path = originalPaths.itemAt(i); - mOriginalPaths.add(path); - caches.resourceCache.incrementRefcount(path); - } - const Vector<SkMatrix*> &matrices = recorder.getMatrices(); for (size_t i = 0; i < matrices.size(); i++) { mMatrices.add(matrices.itemAt(i)); @@ -166,6 +177,331 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde void DisplayList::init() { } +/** + * This function is a simplified version of replay(), where we simply retrieve and log the + * display list. This function should remain in sync with the replay() function. + */ +void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { + TextContainer text; + + uint32_t count = (level + 1) * 2; + char indent[count + 1]; + for (uint32_t i = 0; i < count; i++) { + indent[i] = ' '; + } + indent[count] = '\0'; + LOGD("%sStart display list (%p)", (char*) indent + 2, this); + + int saveCount = renderer.getSaveCount() - 1; + + mReader.rewind(); + + while (!mReader.eof()) { + int op = mReader.readInt(); + + switch (op) { + case DrawGLFunction: { + Functor *functor = (Functor *) getInt(); + LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); + } + break; + case Save: { + int rendererNum = getInt(); + LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); + } + break; + case Restore: { + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case RestoreToCount: { + int restoreCount = saveCount + getInt(); + LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); + } + break; + case SaveLayer: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + int flags = getInt(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, paint, flags); + } + break; + case SaveLayerAlpha: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int alpha = getInt(); + int flags = getInt(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, alpha, flags); + } + break; + case Translate: { + float f1 = getFloat(); + float f2 = getFloat(); + LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2); + } + break; + case Rotate: { + float rotation = getFloat(); + LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation); + } + break; + case Scale: { + float sx = getFloat(); + float sy = getFloat(); + LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + } + break; + case Skew: { + float sx = getFloat(); + float sy = getFloat(); + LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + } + break; + case SetMatrix: { + SkMatrix* matrix = getMatrix(); + LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + } + break; + case ConcatMatrix: { + SkMatrix* matrix = getMatrix(); + LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + } + break; + case ClipRect: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int regionOp = getInt(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, regionOp); + } + break; + case DrawDisplayList: { + DisplayList* displayList = getDisplayList(); + uint32_t width = getUInt(); + uint32_t height = getUInt(); + LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op], + displayList, width, height, level + 1); + renderer.outputDisplayList(displayList, level + 1); + } + break; + case DrawLayer: { + Layer* layer = (Layer*) getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + layer, x, y, paint); + } + break; + case DrawBitmap: { + SkBitmap* bitmap = getBitmap(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + bitmap, x, y, paint); + } + break; + case DrawBitmapMatrix: { + SkBitmap* bitmap = getBitmap(); + SkMatrix* matrix = getMatrix(); + SkPaint* paint = getPaint(); + LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op], + bitmap, matrix, paint); + } + break; + case DrawBitmapRect: { + SkBitmap* bitmap = getBitmap(); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + float f7 = getFloat(); + float f8 = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); + } + break; + case DrawBitmapMesh: { + int verticesCount = 0; + uint32_t colorsCount = 0; + SkBitmap* bitmap = getBitmap(); + uint32_t meshWidth = getInt(); + uint32_t meshHeight = getInt(); + float* vertices = getFloats(verticesCount); + bool hasColors = getInt(); + int* colors = hasColors ? getInts(colorsCount) : NULL; + SkPaint* paint = getPaint(); + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case DrawPatch: { + int32_t* xDivs = NULL; + int32_t* yDivs = NULL; + uint32_t* colors = NULL; + uint32_t xDivsCount = 0; + uint32_t yDivsCount = 0; + int8_t numColors = 0; + SkBitmap* bitmap = getBitmap(); + xDivs = getInts(xDivsCount); + yDivs = getInts(yDivsCount); + colors = getUInts(numColors); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); + getFloat(); + getFloat(); + getFloat(); + getFloat(); + getPaint(); + } + break; + case DrawColor: { + int color = getInt(); + int xferMode = getInt(); + LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); + } + break; + case DrawRect: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, paint); + } + break; + case DrawRoundRect: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint); + } + break; + case DrawCircle: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, paint); + } + break; + case DrawOval: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); + } + break; + case DrawArc: { + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + int i1 = getInt(); + SkPaint* paint = getPaint(); + LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); + } + break; + case DrawPath: { + SkPath* path = getPath(); + SkPaint* paint = getPaint(); + LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint); + } + break; + case DrawLines: { + int count = 0; + float* points = getFloats(count); + SkPaint* paint = getPaint(); + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case DrawPoints: { + int count = 0; + float* points = getFloats(count); + SkPaint* paint = getPaint(); + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case DrawText: { + getText(&text); + int count = getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + text.text(), text.length(), count, x, y, paint); + } + break; + case ResetShader: { + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case SetupShader: { + SkiaShader* shader = getShader(); + LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader); + } + break; + case ResetColorFilter: { + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case SetupColorFilter: { + SkiaColorFilter *colorFilter = getColorFilter(); + LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter); + } + break; + case ResetShadow: { + LOGD("%s%s", (char*) indent, OP_NAMES[op]); + } + break; + case SetupShadow: { + float radius = getFloat(); + float dx = getFloat(); + float dy = getFloat(); + int color = getInt(); + LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], + radius, dx, dy, color); + } + break; + default: + LOGD("Display List error: op not handled: %s%s", + (char*) indent, OP_NAMES[op]); + break; + } + } + + LOGD("%sDone", (char*) indent + 2); +} + +/** + * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked + * in the output() function, since that function processes the same list of opcodes for the + * purposes of logging display list info for a given view. + */ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) { bool needsInvalidate = false; TextContainer text; @@ -181,9 +517,11 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this); #endif + DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); int saveCount = renderer.getSaveCount() - 1; while (!mReader.eof()) { int op = mReader.readInt(); + logBuffer.writeCommand(level, op); switch (op) { case DrawGLFunction: { @@ -452,6 +790,13 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) renderer.drawLines(points, count, getPaint()); } break; + case DrawPoints: { + int count = 0; + float* points = getFloats(count); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); + renderer.drawPoints(points, count, getPaint()); + } + break; case DrawText: { getText(&text); int count = getInt(); @@ -533,12 +878,6 @@ void DisplayListRenderer::reset() { } mBitmapResources.clear(); - for (size_t i = 0; i < mOriginalPaths.size(); i++) { - SkPath* resource = mOriginalPaths.itemAt(i); - caches.resourceCache.decrementRefcount(resource); - } - mOriginalPaths.clear(); - for (size_t i = 0; i < mShaders.size(); i++) { caches.resourceCache.decrementRefcount(mShaders.itemAt(i)); } @@ -804,8 +1143,15 @@ void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { addPaint(paint); } +void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) { + addOp(DisplayList::DrawPoints); + addFloats(points, count); + addPaint(paint); +} + void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint) { + if (count <= 0) return; addOp(DisplayList::DrawText); addText(text, bytesCount); addInt(count); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 6fc315c..dcf2cf2 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -26,6 +26,7 @@ #include <SkTDArray.h> #include <SkTSearch.h> +#include "DisplayListLogBuffer.h" #include "OpenGLRenderer.h" #include "utils/Functor.h" @@ -89,6 +90,7 @@ public: DrawArc, DrawPath, DrawLines, + DrawPoints, DrawText, ResetShader, SetupShader, @@ -105,6 +107,10 @@ public: bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0); + void output(OpenGLRenderer& renderer, uint32_t level = 0); + + static void outputLogBuffer(int fd); + private: void init(); @@ -193,7 +199,6 @@ private: Vector<SkPaint*> mPaints; Vector<SkPath*> mPaths; - Vector<SkPath*> mOriginalPaths; Vector<SkMatrix*> mMatrices; Vector<SkiaShader*> mShaders; @@ -265,6 +270,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); void drawPath(SkPath* path, SkPaint* paint); void drawLines(float* points, int count, SkPaint* paint); + void drawPoints(float* points, int count, SkPaint* paint); void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); void resetShader(); @@ -298,10 +304,6 @@ public: return mPaths; } - const Vector<SkPath*>& getOriginalPaths() const { - return mOriginalPaths; - } - const Vector<SkMatrix*>& getMatrices() const { return mMatrices; } @@ -383,16 +385,9 @@ private: SkPath* pathCopy = mPathMap.valueFor(path); if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) { - if (pathCopy == NULL) { - pathCopy = path; - mOriginalPaths.add(path); - Caches& caches = Caches::getInstance(); - caches.resourceCache.incrementRefcount(path); - } else { - pathCopy = new SkPath(*path); - mPaths.add(pathCopy); - } + pathCopy = new SkPath(*path); mPathMap.add(path, pathCopy); + mPaths.add(pathCopy); } addInt((int) pathCopy); @@ -469,7 +464,6 @@ private: Vector<SkPaint*> mPaints; DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap; - Vector<SkPath*> mOriginalPaths; Vector<SkPath*> mPaths; DefaultKeyedVector<SkPath*, SkPath*> mPathMap; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index aa9b40e..9bf3de8 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -35,6 +35,10 @@ namespace uirenderer { #define DEFAULT_TEXT_CACHE_WIDTH 1024 #define DEFAULT_TEXT_CACHE_HEIGHT 256 +// We should query these values from the GL context +#define MAX_TEXT_CACHE_WIDTH 2048 +#define MAX_TEXT_CACHE_HEIGHT 2048 + /////////////////////////////////////////////////////////////////////////////// // Font /////////////////////////////////////////////////////////////////////////////// @@ -55,8 +59,7 @@ Font::~Font() { } for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { - CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i); - delete glyph; + delete mCachedGlyphs.valueAt(i); } } @@ -131,48 +134,49 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, } -Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) { +Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { CachedGlyphInfo* cachedGlyph = NULL; - ssize_t index = mCachedGlyphs.indexOfKey(utfChar); + ssize_t index = mCachedGlyphs.indexOfKey(textUnit); if (index >= 0) { cachedGlyph = mCachedGlyphs.valueAt(index); } else { - cachedGlyph = cacheGlyph(paint, utfChar); + cachedGlyph = cacheGlyph(paint, textUnit); } // Is the glyph still in texture cache? if (!cachedGlyph->mIsValid) { - const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); + const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit); updateGlyphCache(paint, skiaGlyph, cachedGlyph); } return cachedGlyph; } -void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, +void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { - renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, + render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, bitmapW, bitmapH, NULL); } else { - renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL); + render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, + 0, 0, NULL); } } -void Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, +void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, int numGlyphs, Rect *bounds) { if (bounds == NULL) { LOGE("No return rectangle provided to measure text"); return; } bounds->set(1e6, -1e6, -1e6, 1e6); - renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); + render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); } #define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) -void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, +void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) { if (numGlyphs == 0 || text == NULL || len == 0) { @@ -192,14 +196,14 @@ void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t text += start; while (glyphsLeft > 0) { - int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); + glyph_t glyph = GET_GLYPH(text); // Reached the end of the string - if (utfChar < 0) { + if (IS_END_OF_STRING(glyph)) { break; } - CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); + CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta); prevRsbDelta = cachedGlyph->mRsbDelta; @@ -265,11 +269,11 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp mState->mUploadTexture = true; } -Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { +Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); - const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); + const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph); newGlyph->mGlyphIndex = skiaGlyph.fID; newGlyph->mIsValid = false; @@ -386,9 +390,17 @@ void FontRenderer::flushAllAndInvalidate() { bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { // If the glyph is too tall, don't cache it if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { - LOGE("Font size to large to fit in cache. width, height = %i, %i", - (int) glyph.fWidth, (int) glyph.fHeight); - return false; + if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) { + // Default cache not large enough for large glyphs - resize cache to + // max size and try again + flushAllAndInvalidate(); + initTextTexture(true); + } + if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { + LOGE("Font size to large to fit in cache. width, height = %i, %i", + (int) glyph.fWidth, (int) glyph.fHeight); + return false; + } } // Now copy the bitmap into the cache texture @@ -446,16 +458,25 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3 return true; } -void FontRenderer::initTextTexture() { +void FontRenderer::initTextTexture(bool largeFonts) { + mCacheLines.clear(); + if (largeFonts) { + mCacheWidth = MAX_TEXT_CACHE_WIDTH; + mCacheHeight = MAX_TEXT_CACHE_HEIGHT; + } + mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); mUploadTexture = false; + if (mTextureId != 0) { + glDeleteTextures(1, &mTextureId); + } glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_2D, mTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Initialize texture dimentions + // Initialize texture dimensions glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); @@ -480,6 +501,15 @@ void FontRenderer::initTextTexture() { nextLine += mCacheLines.top()->mMaxHeight; mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); nextLine += mCacheLines.top()->mMaxHeight; + if (largeFonts) { + int nextSize = 76; + // Make several new lines with increasing font sizes + while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) { + mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + nextSize += 50; + } + } mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); } @@ -643,7 +673,7 @@ void FontRenderer::precacheLatin(SkPaint* paint) { uint32_t remainingCapacity = getRemainingCacheCapacity(); uint32_t precacheIdx = 0; while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { - mCurrentFont->getCachedUTFChar(paint, (int32_t) mLatinPrecache[precacheIdx]); + mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]); remainingCapacity = getRemainingCacheCapacity(); precacheIdx ++; } @@ -685,7 +715,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch } Rect bounds; - mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds); + mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds); uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; @@ -696,7 +726,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch int penX = radius - bounds.left; int penY = radius - bounds.bottom; - mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, + mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, dataBuffer, paddedWidth, paddedHeight); blurImage(dataBuffer, paddedWidth, paddedHeight, radius); @@ -726,7 +756,7 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text mDrawn = false; mBounds = bounds; mClip = clip; - mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); + mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); mBounds = NULL; if (mCurrentQuadIndex != 0) { diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index f685d5f..24ed6fa 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -33,8 +33,32 @@ namespace android { namespace uirenderer { +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#if RENDER_TEXT_AS_GLYPHS + typedef uint16_t glyph_t; + #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph) + #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text) + #define IS_END_OF_STRING(glyph) false +#else + typedef SkUnichar glyph_t; + #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph) + #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text) + #define IS_END_OF_STRING(glyph) glyph < 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Declarations +/////////////////////////////////////////////////////////////////////////////// + class FontRenderer; +/////////////////////////////////////////////////////////////////////////////// +// Font +/////////////////////////////////////////////////////////////////////////////// + /** * Represents a font, defined by a Skia font id and a font size. A font is used * to generate glyphs and cache them in the FontState. @@ -51,9 +75,9 @@ public: * Renders the specified string of text. * If bitmap is specified, it will be used as the render target */ - void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len, - int numGlyphs, int x, int y, - uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0); + void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, + int numGlyphs, int x, int y, uint8_t *bitmap = NULL, + uint32_t bitmapW = 0, uint32_t bitmapH = 0); /** * Creates a new font associated with the specified font state. */ @@ -69,13 +93,12 @@ protected: MEASURE, }; - void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len, - int numGlyphs, int x, int y, RenderMode mode, - uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, - Rect *bounds); + void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, + int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, + uint32_t bitmapW, uint32_t bitmapH, Rect *bounds); - void measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, - int numGlyphs, Rect *bounds); + void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, + int numGlyphs, Rect *bounds); struct CachedGlyphInfo { // Has the cache been invalidated? @@ -107,18 +130,26 @@ protected: Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle, uint32_t scaleX); - DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs; + // Cache of glyphs + DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs; void invalidateTextureCache(); - CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_t glyph); + CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph); void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph); void measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds); void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y); void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y, - uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH); + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH); - CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar); + CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit); + + static glyph_t nextGlyph(const uint16_t** srcPtr) { + const uint16_t* src = *srcPtr; + glyph_t g = *src++; + *srcPtr = src; + return g; + } FontRenderer* mState; uint32_t mFontId; @@ -128,6 +159,10 @@ protected: uint32_t mScaleX; }; +/////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////// + class FontRenderer { public: FontRenderer(); @@ -229,7 +264,7 @@ protected: } }; - void initTextTexture(); + void initTextTexture(bool largeFonts = false); bool cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY); void flushAllAndInvalidate(); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index bb28437..0310bc3 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -45,6 +45,9 @@ struct Layer { mesh = NULL; meshIndices = NULL; meshElementCount = 0; + isCacheable = true; + isTextureLayer = false; + renderTarget = GL_TEXTURE_2D; } ~Layer() { @@ -53,6 +56,23 @@ struct Layer { } /** + * Sets this layer's region to a rectangle. Computes the appropriate + * texture coordinates. + */ + void setRegionAsRect() { + const android::Rect& bounds = region.getBounds(); + regionRect.set(bounds.leftTop().x, bounds.leftTop().y, + bounds.rightBottom().x, bounds.rightBottom().y); + + const float texX = 1.0f / float(width); + const float texY = 1.0f / float(height); + const float height = layer.getHeight(); + texCoords.set( + regionRect.left * texX, (height - regionRect.top) * texY, + regionRect.right * texX, (height - regionRect.bottom) * texY); + } + + /** * Bounds of the layer. */ Rect layer; @@ -103,6 +123,11 @@ struct Layer { * have been drawn. */ Region region; + /** + * If the region is a rectangle, coordinates of the + * region are stored here. + */ + Rect regionRect; /** * Color filter used to draw this layer. Optional. @@ -115,6 +140,27 @@ struct Layer { TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; + + /** + * If set to true (by default), the layer can be reused. + */ + bool isCacheable; + + /** + * When set to true, this layer must be treated as a texture + * layer. + */ + bool isTextureLayer; + + /** + * Optional texture coordinates transform. + */ + mat4 texTransform; + + /** + * Indicates the render target. + */ + GLenum renderTarget; }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index a9710ad..b2d795f 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -154,6 +154,8 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh } bool LayerCache::put(Layer* layer) { + if (!layer->isCacheable) return false; + const uint32_t size = layer->width * layer->height * 4; // Don't even try to cache a layer that's bigger than the cache if (size < mMaxSize) { diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f92e20b..f316ba7 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -20,6 +20,7 @@ #include "LayerCache.h" #include "LayerRenderer.h" +#include "Matrix.h" #include "Properties.h" #include "Rect.h" @@ -92,11 +93,7 @@ Region* LayerRenderer::getRegion() { void LayerRenderer::generateMesh() { #if RENDER_LAYERS_AS_REGIONS -#if RENDER_LAYERS_RECT_AS_RECT if (mLayer->region.isRect() || mLayer->region.isEmpty()) { -#else - if (mLayer->region.isEmpty()) { -#endif if (mLayer->mesh) { delete mLayer->mesh; delete mLayer->meshIndices; @@ -105,6 +102,8 @@ void LayerRenderer::generateMesh() { mLayer->meshIndices = NULL; mLayer->meshElementCount = 0; } + + mLayer->setRegionAsRect(); return; } @@ -167,6 +166,30 @@ void LayerRenderer::generateMesh() { // Layers management /////////////////////////////////////////////////////////////////////////////// +Layer* LayerRenderer::createTextureLayer() { + LAYER_RENDERER_LOGD("Creating new texture layer"); + + Layer* layer = new Layer(0, 0); + layer->isCacheable = false; + layer->isTextureLayer = true; + layer->blend = true; + layer->empty = true; + layer->fbo = 0; + layer->colorFilter = NULL; + layer->fbo = 0; + layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); + layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f); + layer->alpha = 255; + layer->mode = SkXfermode::kSrcOver_Mode; + layer->colorFilter = NULL; + layer->region.clear(); + + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &layer->texture); + + return layer; +} + Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); @@ -246,6 +269,27 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { return true; } +void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, + GLenum renderTarget, float* transform) { + if (layer) { + layer->width = width; + layer->height = height; + layer->layer.set(0.0f, 0.0f, width, height); + layer->region.set(width, height); + layer->regionRect.set(0.0f, 0.0f, width, height); + layer->texTransform.load(transform); + layer->renderTarget = renderTarget; + + glBindTexture(layer->renderTarget, layer->texture); + + glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } +} + void LayerRenderer::destroyLayer(Layer* layer) { if (layer) { LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index d2f565e..59cab96 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -53,8 +53,11 @@ public: Region* getRegion(); GLint getTargetFbo(); + static Layer* createTextureLayer(); static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); + static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, + GLenum renderTarget, float* transform); static void destroyLayer(Layer* layer); static void destroyLayerDeferred(Layer* layer); diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index e7c0fe3..9fc5131 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -67,6 +67,10 @@ bool Matrix4::isPureTranslate() { ALMOST_EQUAL(data[kScaleX], 1.0f) && ALMOST_EQUAL(data[kScaleY], 1.0f); } +bool Matrix4::isSimple() { + return mSimpleMatrix; +} + void Matrix4::load(const float* v) { memcpy(data, v, sizeof(data)); mSimpleMatrix = false; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 08f5d77..2fa6ab7 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -111,6 +111,7 @@ public: } bool isPureTranslate(); + bool isSimple(); bool changesBounds(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index d9d7d23..6c9c0eb 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -63,7 +63,7 @@ struct Blender { // In this array, the index of each Blender equals the value of the first // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] static const Blender gBlends[] = { - { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, + { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, @@ -81,7 +81,7 @@ static const Blender gBlends[] = { // this array's SrcOver blending mode is actually DstOver. You can refer to // createLayer() for more information on the purpose of this array. static const Blender gBlendsSwap[] = { - { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, + { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, @@ -633,26 +633,64 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { } } +void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { + float alpha = layer->alpha / 255.0f; + + setupDraw(); + if (layer->renderTarget == GL_TEXTURE_2D) { + setupDrawWithTexture(); + } else { + setupDrawWithExternalTexture(); + } + setupDrawTextureTransform(); + setupDrawColor(alpha, alpha, alpha, alpha); + setupDrawColorFilter(); + setupDrawBlending(layer->blend, layer->mode); + setupDrawProgram(); + setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + if (layer->renderTarget == GL_TEXTURE_2D) { + setupDrawTexture(layer->texture); + } else { + setupDrawExternalTexture(layer->texture); + } + setupDrawTextureTransformUniforms(layer->texTransform); + setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + + finishDrawTexture(); +} + void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { - const Rect& texCoords = layer->texCoords; - resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); + if (!layer->isTextureLayer) { + const Rect& texCoords = layer->texCoords; + resetDrawTextureTexCoords(texCoords.left, texCoords.top, + texCoords.right, texCoords.bottom); - drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, - layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], - &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap); + drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, + layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], + &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap); - resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); + resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); + } else { + resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); + drawTextureLayer(layer, rect); + resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); + } } void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { #if RENDER_LAYERS_AS_REGIONS -#if RENDER_LAYERS_RECT_AS_RECT if (layer->region.isRect()) { - composeLayerRect(layer, rect); + layer->setRegionAsRect(); + + composeLayerRect(layer, layer->regionRect); + layer->region.clear(); return; } -#endif if (!layer->region.isEmpty()) { size_t count; @@ -881,12 +919,27 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { mDescription.hasAlpha8Texture = isAlpha8; } +void OpenGLRenderer::setupDrawWithExternalTexture() { + mDescription.hasExternalTexture = true; +} + +void OpenGLRenderer::setupDrawAALine() { + mDescription.isAA = true; +} + +void OpenGLRenderer::setupDrawPoint(float pointSize) { + mDescription.isPoint = true; + mDescription.pointSize = pointSize; +} + void OpenGLRenderer::setupDrawColor(int color) { setupDrawColor(color, (color >> 24) & 0xFF); } void OpenGLRenderer::setupDrawColor(int color, int alpha) { mColorA = alpha / 255.0f; + // Second divide of a by 255 is an optimization, allowing us to simply multiply + // the rgb values by a instead of also dividing by 255 const float a = mColorA / 255.0f; mColorR = a * ((color >> 16) & 0xFF); mColorG = a * ((color >> 8) & 0xFF); @@ -897,6 +950,8 @@ void OpenGLRenderer::setupDrawColor(int color, int alpha) { void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { mColorA = alpha / 255.0f; + // Double-divide of a by 255 is an optimization, allowing us to simply multiply + // the rgb values by a instead of also dividing by 255 const float a = mColorA / 255.0f; mColorR = a * ((color >> 16) & 0xFF); mColorG = a * ((color >> 8) & 0xFF); @@ -935,12 +990,26 @@ void OpenGLRenderer::setupDrawColorFilter() { } } +void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { + if (mColorSet && mode == SkXfermode::kClear_Mode) { + mColorA = 1.0f; + mColorR = mColorG = mColorB = 0.0f; + mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA); + } +} + void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) { + // When the blending mode is kClear_Mode, we need to use a modulate color + // argb=1,0,0,0 + accountForClear(mode); chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode, mDescription, swapSrcDst); } void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) { + // When the blending mode is kClear_Mode, we need to use a modulate color + // argb=1,0,0,0 + accountForClear(mode); chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode, mDescription, swapSrcDst); } @@ -965,8 +1034,8 @@ void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float ri } } -void OpenGLRenderer::setupDrawModelViewIdentity() { - mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform); +void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) { + mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform, offset); } void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom, @@ -989,6 +1058,11 @@ void OpenGLRenderer::setupDrawModelView(float left, float top, float right, floa } } +void OpenGLRenderer::setupDrawPointUniforms() { + int slot = mCaches.currentProgram->getUniform("pointSize"); + glUniform1f(slot, mDescription.pointSize); +} + void OpenGLRenderer::setupDrawColorUniforms() { if (mColorSet || (mShader && mSetShaderColor)) { mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); @@ -1036,6 +1110,23 @@ void OpenGLRenderer::setupDrawTexture(GLuint texture) { glEnableVertexAttribArray(mTexCoordsSlot); } +void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { + bindExternalTexture(texture); + glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++); + + mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); + glEnableVertexAttribArray(mTexCoordsSlot); +} + +void OpenGLRenderer::setupDrawTextureTransform() { + mDescription.hasTextureTransform = true; +} + +void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { + glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, + GL_FALSE, &transform.data[0]); +} + void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { if (!vertices) { mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); @@ -1049,6 +1140,41 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v } } +void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { + mCaches.unbindMeshBuffer(); + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, + gVertexStride, vertices); +} + +/** + * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an + * outer boundary that fades out to 0. The variables set in the shader define the proportion of + * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength + * attributes (one per vertex) are values from zero to one that tells the fragment + * shader where the fragment is in relation to the line width/length overall; these values are + * then used to compute the proper color, based on whether the fragment lies in the fading AA + * region of the line. + * Note that we only pass down the width values in this setup function. The length coordinates + * are set up for each individual segment. + */ +void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords, + GLvoid* lengthCoords, float boundaryWidthProportion) { + mCaches.unbindMeshBuffer(); + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, + gAAVertexStride, vertices); + int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth"); + glEnableVertexAttribArray(widthSlot); + glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords); + int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength"); + glEnableVertexAttribArray(lengthSlot); + glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords); + int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); + glUniform1f(boundaryWidthSlot, boundaryWidthProportion); + // Setting the inverse value saves computations per-fragment in the shader + int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth"); + glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidthProportion)); +} + void OpenGLRenderer::finishDrawTexture() { glDisableVertexAttribArray(mTexCoordsSlot); } @@ -1072,6 +1198,50 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u return false; } +void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) { + if (displayList) { + displayList->output(*this, level); + } +} + +void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) { + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); + + float x = left; + float y = top; + + bool ignoreTransform = false; + if (mSnapshot->transform->isPureTranslate()) { + x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); + ignoreTransform = true; + } + + setupDraw(); + setupDrawWithTexture(true); + if (paint) { + setupDrawAlpha8Color(paint->getColor(), alpha); + } + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform); + setupDrawTexture(texture->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + + finishDrawTexture(); +} + void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { const float right = left + bitmap->width(); const float bottom = top + bitmap->height(); @@ -1085,7 +1255,11 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint if (!texture) return; const AutoTexture autoCleanup(texture); - drawTextureRect(left, top, right, bottom, texture, paint); + if (bitmap->getConfig() == SkBitmap::kA8_Config) { + drawAlphaBitmap(texture, left, top, paint); + } else { + drawTextureRect(left, top, right, bottom, texture, paint); + } } void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { @@ -1209,10 +1383,10 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const float width = texture->width; const float height = texture->height; - const float u1 = srcLeft / width; - const float v1 = srcTop / height; - const float u2 = srcRight / width; - const float v2 = srcBottom / height; + const float u1 = (srcLeft + 0.5f) / width; + const float v1 = (srcTop + 0.5f) / height; + const float u2 = (srcRight - 0.5f) / width; + const float v2 = (srcBottom - 0.5f) / height; mCaches.unbindMeshBuffer(); resetDrawTextureTexCoords(u1, v1, u2, v2); @@ -1297,117 +1471,375 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } } +/** + * This function uses a similar approach to that of AA lines in the drawLines() function. + * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment + * shader to compute the translucency of the color, determined by whether a given pixel is + * within that boundary region and how far into the region it is. + */ +void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom, + int color, SkXfermode::Mode mode) { + float inverseScaleX = 1.0f; + float inverseScaleY = 1.0f; + // The quad that we use needs to account for scaling. + if (!mSnapshot->transform->isPureTranslate()) { + Matrix4 *mat = mSnapshot->transform; + float m00 = mat->data[Matrix4::kScaleX]; + float m01 = mat->data[Matrix4::kSkewY]; + float m02 = mat->data[2]; + float m10 = mat->data[Matrix4::kSkewX]; + float m11 = mat->data[Matrix4::kScaleX]; + float m12 = mat->data[6]; + float scaleX = sqrt(m00 * m00 + m01 * m01); + float scaleY = sqrt(m10 * m10 + m11 * m11); + inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; + inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; + } + + setupDraw(); + setupDrawAALine(); + setupDrawColor(color); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelViewIdentity(true); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderIdentityUniforms(); + + AAVertex rects[4]; + AAVertex* aaVertices = &rects[0]; + void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; + void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; + + float boundarySizeX = .5 * inverseScaleX; + float boundarySizeY = .5 * inverseScaleY; + + // Adjust the rect by the AA boundary padding + left -= boundarySizeX; + right += boundarySizeX; + top -= boundarySizeY; + bottom += boundarySizeY; + + float width = right - left; + float height = bottom - top; + + float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0; + float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0; + setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, boundaryWidthProportion); + int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); + int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength"); + glUniform1f(boundaryLengthSlot, boundaryHeightProportion); + glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryHeightProportion)); + + if (!quickReject(left, top, right, bottom)) { + AAVertex::set(aaVertices++, left, bottom, 1, 1); + AAVertex::set(aaVertices++, left, top, 1, 0); + AAVertex::set(aaVertices++, right, bottom, 0, 1); + AAVertex::set(aaVertices++, right, top, 0, 0); + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } +} + +/** + * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization + * rules for those lines produces some unexpected results, and may vary between hardware devices. + * The basics of lines-as-quads is easy; we simply find the normal to the line and position the + * corners of the quads on either side of each line endpoint, separated by the strokeWidth + * of the line. Hairlines are more involved because we need to account for transform scaling + * to end up with a one-pixel-wide line in screen space.. + * Anti-aliased lines add another factor to the approach. We use a specialized fragment shader + * in combination with values that we calculate and pass down in this method. The basic approach + * is that the quad we create contains both the core line area plus a bounding area in which + * the translucent/AA pixels are drawn. The values we calculate tell the shader what + * proportion of the width and the length of a given segment is represented by the boundary + * region. The quad ends up being exactly .5 pixel larger in all directions than the non-AA quad. + * The bounding region is actually 1 pixel wide on all sides (half pixel on the outside, half pixel + * on the inside). This ends up giving the result we want, with pixels that are completely + * 'inside' the line area being filled opaquely and the other pixels being filled according to + * how far into the boundary region they are, which is determined by shader interpolation. + */ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (mSnapshot->isIgnored()) return; const bool isAA = paint->isAntiAlias(); - const float strokeWidth = paint->getStrokeWidth() * 0.5f; - // A stroke width of 0 has a special meaningin Skia: - // it draws an unscaled 1px wide line - const bool isHairLine = paint->getStrokeWidth() == 0.0f; - + // We use half the stroke width here because we're going to position the quad + // corner vertices half of the width away from the line endpoints + float halfStrokeWidth = paint->getStrokeWidth() * 0.5f; + // A stroke width of 0 has a special meaning in Skia: + // it draws a line 1 px wide regardless of current transform + bool isHairLine = paint->getStrokeWidth() == 0.0f; + float inverseScaleX = 1.0f; + float inverseScaleY = 1.0f; + bool scaled = false; int alpha; SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); - - int verticesCount = count >> 2; int generatedVerticesCount = 0; - if (!isHairLine) { - // TODO: AA needs more vertices - verticesCount *= 6; - } else { - // TODO: AA will be different - verticesCount *= 2; + int verticesCount = count; + if (count > 4) { + // Polyline: account for extra vertices needed for continuous tri-strip + verticesCount += (count - 4); + } + + if (isHairLine || isAA) { + // The quad that we use for AA and hairlines needs to account for scaling. For hairlines + // the line on the screen should always be one pixel wide regardless of scale. For + // AA lines, we only want one pixel of translucent boundary around the quad. + if (!mSnapshot->transform->isPureTranslate()) { + Matrix4 *mat = mSnapshot->transform; + float m00 = mat->data[Matrix4::kScaleX]; + float m01 = mat->data[Matrix4::kSkewY]; + float m02 = mat->data[2]; + float m10 = mat->data[Matrix4::kSkewX]; + float m11 = mat->data[Matrix4::kScaleX]; + float m12 = mat->data[6]; + float scaleX = sqrt(m00*m00 + m01*m01); + float scaleY = sqrt(m10*m10 + m11*m11); + inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; + inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; + if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) { + scaled = true; + } + } } - TextureVertex lines[verticesCount]; - TextureVertex* vertex = &lines[0]; - + getAlphaAndMode(paint, &alpha, &mode); setupDraw(); + if (isAA) { + setupDrawAALine(); + } setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); - setupDrawBlending(mode); + if (isAA) { + setupDrawBlending(true, mode); + } else { + setupDrawBlending(mode); + } setupDrawProgram(); - setupDrawModelViewIdentity(); + setupDrawModelViewIdentity(true); setupDrawColorUniforms(); setupDrawColorFilterUniforms(); setupDrawShaderIdentityUniforms(); - setupDrawMesh(vertex); - if (!isHairLine) { - // TODO: Handle the AA case - for (int i = 0; i < count; i += 4) { - // a = start point, b = end point - vec2 a(points[i], points[i + 1]); - vec2 b(points[i + 2], points[i + 3]); - - // Bias to snap to the same pixels as Skia - a += 0.375; - b += 0.375; - - // Find the normal to the line - vec2 n = (b - a).copyNormalized() * strokeWidth; - float x = n.x; - n.x = -n.y; - n.y = x; - - // Four corners of the rectangle defining a thick line - vec2 p1 = a - n; - vec2 p2 = a + n; - vec2 p3 = b + n; - vec2 p4 = b - n; - - const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); - const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); - const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); - const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); - - if (!quickReject(left, top, right, bottom)) { - // Draw the line as 2 triangles, could be optimized - // by using only 4 vertices and the correct indices - // Also we should probably used non textured vertices - // when line AA is disabled to save on bandwidth - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p2.x, p2.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p1.x, p1.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p3.x, p3.y, 0.0f, 0.0f); - TextureVertex::set(vertex++, p4.x, p4.y, 0.0f, 0.0f); - - generatedVerticesCount += 6; - - dirtyLayer(left, top, right, bottom, *mSnapshot->transform); + if (isHairLine) { + // Set a real stroke width to be used in quad construction + halfStrokeWidth = isAA? 1 : .5; + } else if (isAA && !scaled) { + // Expand boundary to enable AA calculations on the quad border + halfStrokeWidth += .5f; + } + Vertex lines[verticesCount]; + Vertex* vertices = &lines[0]; + AAVertex wLines[verticesCount]; + AAVertex* aaVertices = &wLines[0]; + if (!isAA) { + setupDrawVertices(vertices); + } else { + void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; + void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; + // innerProportion is the ratio of the inner (non-AA) part of the line to the total + // AA stroke width (the base stroke width expanded by a half pixel on either side). + // This value is used in the fragment shader to determine how to fill fragments. + // We will need to calculate the actual width proportion on each segment for + // scaled non-hairlines, since the boundary proportion may differ per-axis when scaled. + float boundaryWidthProportion = 1 / (2 * halfStrokeWidth); + setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, boundaryWidthProportion); + } + + AAVertex* prevAAVertex = NULL; + Vertex* prevVertex = NULL; + + int boundaryLengthSlot = -1; + int inverseBoundaryLengthSlot = -1; + int boundaryWidthSlot = -1; + int inverseBoundaryWidthSlot = -1; + for (int i = 0; i < count; i += 4) { + // a = start point, b = end point + vec2 a(points[i], points[i + 1]); + vec2 b(points[i + 2], points[i + 3]); + float length = 0; + float boundaryLengthProportion = 0; + float boundaryWidthProportion = 0; + + // Find the normal to the line + vec2 n = (b - a).copyNormalized() * halfStrokeWidth; + if (isHairLine) { + if (isAA) { + float wideningFactor; + if (fabs(n.x) >= fabs(n.y)) { + wideningFactor = fabs(1.0f / n.x); + } else { + wideningFactor = fabs(1.0f / n.y); + } + n *= wideningFactor; + } + if (scaled) { + n.x *= inverseScaleX; + n.y *= inverseScaleY; + } + } else if (scaled) { + // Extend n by .5 pixel on each side, post-transform + vec2 extendedN = n.copyNormalized(); + extendedN /= 2; + extendedN.x *= inverseScaleX; + extendedN.y *= inverseScaleY; + float extendedNLength = extendedN.length(); + // We need to set this value on the shader prior to drawing + boundaryWidthProportion = extendedNLength / (halfStrokeWidth + extendedNLength); + n += extendedN; + } + float x = n.x; + n.x = -n.y; + n.y = x; + + // aa lines expand the endpoint vertices to encompass the AA boundary + if (isAA) { + vec2 abVector = (b - a); + length = abVector.length(); + abVector.normalize(); + if (scaled) { + abVector.x *= inverseScaleX; + abVector.y *= inverseScaleY; + float abLength = abVector.length(); + boundaryLengthProportion = abLength / (length + abLength); + } else { + boundaryLengthProportion = .5 / (length + 1); } + abVector /= 2; + a -= abVector; + b += abVector; } - if (generatedVerticesCount > 0) { - // GL_LINE does not give the result we want to match Skia - glDrawArrays(GL_TRIANGLES, 0, generatedVerticesCount); + // Four corners of the rectangle defining a thick line + vec2 p1 = a - n; + vec2 p2 = a + n; + vec2 p3 = b + n; + vec2 p4 = b - n; + + + const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); + const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); + const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); + const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); + + if (!quickReject(left, top, right, bottom)) { + if (!isAA) { + if (prevVertex != NULL) { + // Issue two repeat vertices to create degenerate triangles to bridge + // between the previous line and the new one. This is necessary because + // we are creating a single triangle_strip which will contain + // potentially discontinuous line segments. + Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]); + Vertex::set(vertices++, p1.x, p1.y); + generatedVerticesCount += 2; + } + Vertex::set(vertices++, p1.x, p1.y); + Vertex::set(vertices++, p2.x, p2.y); + Vertex::set(vertices++, p4.x, p4.y); + Vertex::set(vertices++, p3.x, p3.y); + prevVertex = vertices - 1; + generatedVerticesCount += 4; + } else { + if (!isHairLine && scaled) { + // Must set width proportions per-segment for scaled non-hairlines to use the + // correct AA boundary dimensions + if (boundaryWidthSlot < 0) { + boundaryWidthSlot = + mCaches.currentProgram->getUniform("boundaryWidth"); + inverseBoundaryWidthSlot = + mCaches.currentProgram->getUniform("inverseBoundaryWidth"); + } + glUniform1f(boundaryWidthSlot, boundaryWidthProportion); + glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidthProportion)); + } + if (boundaryLengthSlot < 0) { + boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); + inverseBoundaryLengthSlot = + mCaches.currentProgram->getUniform("inverseBoundaryLength"); + } + glUniform1f(boundaryLengthSlot, boundaryLengthProportion); + glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLengthProportion)); + + if (prevAAVertex != NULL) { + // Issue two repeat vertices to create degenerate triangles to bridge + // between the previous line and the new one. This is necessary because + // we are creating a single triangle_strip which will contain + // potentially discontinuous line segments. + AAVertex::set(aaVertices++,prevAAVertex->position[0], + prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length); + AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); + generatedVerticesCount += 2; + } + AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); + AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0); + AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1); + AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0); + prevAAVertex = aaVertices - 1; + generatedVerticesCount += 4; + } + dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top, + a.x == b.x ? right: right, a.y == b.y ? bottom: bottom, + *mSnapshot->transform); } - } else { - // TODO: Handle the AA case - for (int i = 0; i < count; i += 4) { - const float left = fmin(points[i], points[i + 1]); - const float right = fmax(points[i], points[i + 1]); - const float top = fmin(points[i + 2], points[i + 3]); - const float bottom = fmax(points[i + 2], points[i + 3]); + } + if (generatedVerticesCount > 0) { + glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount); + } +} + +void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { + if (mSnapshot->isIgnored()) return; - if (!quickReject(left, top, right, bottom)) { - TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); - TextureVertex::set(vertex++, points[i + 2], points[i + 3], 0.0f, 0.0f); + // TODO: The paint's cap style defines whether the points are square or circular + // TODO: Handle AA for round points - generatedVerticesCount += 2; + // A stroke width of 0 has a special meaning in Skia: + // it draws an unscaled 1px point + float strokeWidth = paint->getStrokeWidth(); + const bool isHairLine = paint->getStrokeWidth() == 0.0f; + if (isHairLine) { + // Now that we know it's hairline, we can set the effective width, to be used later + strokeWidth = 1.0f; + } + const float halfWidth = strokeWidth / 2; + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); - dirtyLayer(left, top, right, bottom, *mSnapshot->transform); - } - } + int verticesCount = count >> 1; + int generatedVerticesCount = 0; - if (generatedVerticesCount > 0) { - glLineWidth(1.0f); - glDrawArrays(GL_LINES, 0, generatedVerticesCount); - } + TextureVertex pointsData[verticesCount]; + TextureVertex* vertex = &pointsData[0]; + + setupDraw(); + setupDrawPoint(strokeWidth); + setupDrawColor(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(mode); + setupDrawProgram(); + setupDrawModelViewIdentity(true); + setupDrawColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawPointUniforms(); + setupDrawShaderIdentityUniforms(); + setupDrawMesh(vertex); + + for (int i = 0; i < count; i += 2) { + TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); + generatedVerticesCount++; + float left = points[i] - halfWidth; + float right = points[i] + halfWidth; + float top = points[i + 1] - halfWidth; + float bottom = points [i + 1] + halfWidth; + dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } + + glDrawArrays(GL_POINTS, 0, generatedVerticesCount); } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { @@ -1502,7 +1934,11 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, } int color = p->getColor(); - drawColorRect(left, top, right, bottom, color, mode); + if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) { + drawAARect(left, top, right, bottom, color, mode); + } else { + drawColorRect(left, top, right, bottom, color, mode); + } } void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, @@ -1512,7 +1948,16 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, } if (mSnapshot->isIgnored()) return; + // TODO: We should probably make a copy of the paint instead of modifying + // it; modifying the paint will change its generationID the first + // time, which might impact caches. More investigation needed to + // see if it matters. + // If we make a copy, then drawTextDecorations() should *not* make + // its own copy as it does right now. paint->setAntiAlias(true); +#if RENDER_TEXT_AS_GLYPHS + paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); +#endif float length = -1.0f; switch (paint->getTextAlign()) { @@ -1546,27 +1991,36 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, if (mHasShadow) { mCaches.dropShadowCache.setFontRenderer(fontRenderer); - const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, - count, mShadowRadius); + const ShadowTexture* shadow = mCaches.dropShadowCache.get( + paint, text, bytesCount, count, mShadowRadius); const AutoTexture autoCleanup(shadow); - const float sx = x - shadow->left + mShadowDx; - const float sy = y - shadow->top + mShadowDy; + const float sx = oldX - shadow->left + mShadowDx; + const float sy = oldY - shadow->top + mShadowDy; const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); + int shadowColor = mShadowColor; + if (mShader) { + shadowColor = 0xffffffff; + } glActiveTexture(gTextureUnits[0]); setupDraw(); setupDrawWithTexture(true); - setupDrawAlpha8Color(mShadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); + setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); + setupDrawColorFilter(); + setupDrawShader(); setupDrawBlending(true, mode); setupDrawProgram(); - setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height, pureTranslate); + setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); setupDrawTexture(shadow->id); setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + finishDrawTexture(); } @@ -1658,14 +2112,9 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { #if RENDER_LAYERS_AS_REGIONS if (!layer->region.isEmpty()) { -#if RENDER_LAYERS_RECT_AS_RECT if (layer->region.isRect()) { - const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); - composeLayerRect(layer, r); + composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { -#else - if (layer->mesh) { -#endif const float a = alpha / 255.0f; const Rect& rect = layer->layer; @@ -1675,13 +2124,11 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { setupDrawColorFilter(); setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false); setupDrawProgram(); + setupDrawModelViewTranslate(x, y, + x + layer->layer.getWidth(), y + layer->layer.getHeight()); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawTexture(layer->texture); - // TODO: The current layer, if any, will be dirtied with the bounding box - // of the layer we are drawing. Since the layer we are drawing has - // a mesh, we know the dirty region, we should use it instead - setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); glDrawElements(GL_TRIANGLES, layer->meshElementCount, @@ -1786,14 +2233,15 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float // Handle underline and strike-through uint32_t flags = paint->getFlags(); if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + SkPaint paintCopy(*paint); float underlineWidth = length; // If length is > 0.0f, we already measured the text for the text alignment if (length <= 0.0f) { - underlineWidth = paint->measureText(text, bytesCount); + underlineWidth = paintCopy.measureText(text, bytesCount); } float offsetX = 0; - switch (paint->getTextAlign()) { + switch (paintCopy.getTextAlign()) { case SkPaint::kCenter_Align: offsetX = underlineWidth * 0.5f; break; @@ -1805,8 +2253,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float } if (underlineWidth > 0.0f) { - const float textSize = paint->getTextSize(); - // TODO: Support stroke width < 1.0f when we have AA lines + const float textSize = paintCopy.getTextSize(); const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); const float left = x - offsetX; @@ -1836,10 +2283,9 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float points[currentPoint++] = top; } - SkPaint linesPaint(*paint); - linesPaint.setStrokeWidth(strokeWidth); + paintCopy.setStrokeWidth(strokeWidth); - drawLines(&points[0], pointsCount, &linesPaint); + drawLines(&points[0], pointsCount, &paintCopy); } } } @@ -2004,12 +2450,11 @@ void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mod } SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { - // In the future we should look at unifying the Porter-Duff modes and - // SkXferModes so that we can use SkXfermode::IsMode(xfer, &mode). - if (mode == NULL) { - return SkXfermode::kSrcOver_Mode; + SkXfermode::Mode resultMode; + if (!SkXfermode::AsMode(mode, &resultMode)) { + resultMode = SkXfermode::kSrcOver_Mode; } - return mode->fMode; + return resultMode; } void OpenGLRenderer::setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 7362473..549d6e9 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -98,6 +98,7 @@ public: virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height, Rect& dirty, uint32_t level = 0); + virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0); virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); @@ -119,6 +120,7 @@ public: float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); virtual void drawPath(SkPath* path, SkPaint* paint); virtual void drawLines(float* points, int count, SkPaint* paint); + virtual void drawPoints(float* points, int count, SkPaint* paint); virtual void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); @@ -247,6 +249,8 @@ private: */ void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false); + void drawTextureLayer(Layer* layer, const Rect& rect); + /** * Mark the layer as dirty at the specified coordinates. The coordinates * are transformed with the supplied matrix. @@ -279,6 +283,11 @@ private: void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint); void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p); + void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint); + + void drawAARect(float left, float top, float right, float bottom, + int color, SkXfermode::Mode mode); + /** * Draws a textured rectangle with the specified texture. The specified coordinates * are transformed by the current snapshot's transform matrix. @@ -384,6 +393,14 @@ private: } /** + * Binds the specified EGLImage texture. The texture unit must have been selected + * prior to calling this method. + */ + inline void bindExternalTexture(GLuint texture) { + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); + } + + /** * Sets the wrap modes for the specified texture. The wrap modes are modified * only when needed. */ @@ -422,6 +439,9 @@ private: * Various methods to setup OpenGL rendering. */ void setupDrawWithTexture(bool isAlpha8 = false); + void setupDrawWithExternalTexture(); + void setupDrawAALine(); + void setupDrawPoint(float pointSize); void setupDrawColor(int color); void setupDrawColor(int color, int alpha); void setupDrawColor(float r, float g, float b, float a); @@ -435,11 +455,12 @@ private: bool swapSrcDst = false); void setupDrawProgram(); void setupDrawDirtyRegionsDisabled(); - void setupDrawModelViewIdentity(); + void setupDrawModelViewIdentity(bool offset = false); void setupDrawModelView(float left, float top, float right, float bottom, bool ignoreTransform = false, bool ignoreModelView = false); void setupDrawModelViewTranslate(float left, float top, float right, float bottom, bool ignoreTransform = false); + void setupDrawPointUniforms(); void setupDrawColorUniforms(); void setupDrawPureColorUniforms(); void setupDrawShaderIdentityUniforms(); @@ -447,8 +468,15 @@ private: void setupDrawColorFilterUniforms(); void setupDrawSimpleMesh(); void setupDrawTexture(GLuint texture); + void setupDrawExternalTexture(GLuint texture); + void setupDrawTextureTransform(); + void setupDrawTextureTransformUniforms(mat4& transform); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); + void setupDrawVertices(GLvoid* vertices); + void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords, + float strokeWidth); void finishDrawTexture(); + void accountForClear(SkXfermode::Mode mode); void drawRegionRects(const Region& region); diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 11eb953..f7dacae 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -152,12 +152,12 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, float previousStepY = 0.0f; float y1 = 0.0f; + float y2 = 0.0f; float v1 = 0.0f; for (uint32_t i = 0; i < mYCount; i++) { float stepY = mYDivs[i]; - float y2 = 0.0f; if (i & 1) { const float segment = stepY - previousStepY; y2 = y1 + floorf(segment * stretchY + 0.5f); @@ -167,8 +167,15 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight; if (stepY > 0.0f) { +#if DEBUG_EXPLODE_PATCHES + y1 += i * EXPLODE_GAP; + y2 += i * EXPLODE_GAP; +#endif generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount); +#if DEBUG_EXPLODE_PATCHES + y2 -= i * EXPLODE_GAP; +#endif } y1 = y2; @@ -178,7 +185,12 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, } if (previousStepY != bitmapHeight) { - generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left, + y2 = bottom - top; +#if DEBUG_EXPLODE_PATCHES + y1 += mYCount * EXPLODE_GAP; + y2 += mYCount * EXPLODE_GAP; +#endif + generateRow(vertex, y1, y2, v1, 1.0f, stretchX, right - left, bitmapWidth, quadCount); } @@ -202,13 +214,13 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl float previousStepX = 0.0f; float x1 = 0.0f; + float x2 = 0.0f; float u1 = 0.0f; // Generate the row quad by quad for (uint32_t i = 0; i < mXCount; i++) { float stepX = mXDivs[i]; - float x2 = 0.0f; if (i & 1) { const float segment = stepX - previousStepX; x2 = x1 + floorf(segment * stretchX + 0.5f); @@ -218,7 +230,14 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth; if (stepX > 0.0f) { +#if DEBUG_EXPLODE_PATCHES + x1 += i * EXPLODE_GAP; + x2 += i * EXPLODE_GAP; +#endif generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); +#if DEBUG_EXPLODE_PATCHES + x2 -= i * EXPLODE_GAP; +#endif } x1 = x2; @@ -228,7 +247,12 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl } if (previousStepX != bitmapWidth) { - generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount); + x2 = width; +#if DEBUG_EXPLODE_PATCHES + x1 += mXCount * EXPLODE_GAP; + x2 += mXCount * EXPLODE_GAP; +#endif + generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount); } } diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h index 0f0ffa2..28c9048 100644 --- a/libs/hwui/Patch.h +++ b/libs/hwui/Patch.h @@ -31,6 +31,12 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define EXPLODE_GAP 4 + +/////////////////////////////////////////////////////////////////////////////// // 9-patch structures /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index dc67e16..7ff8b74 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -41,8 +41,7 @@ struct PathCacheEntry: public ShapeCacheEntry { path = NULL; } - PathCacheEntry(const PathCacheEntry& entry): - ShapeCacheEntry(entry) { + PathCacheEntry(const PathCacheEntry& entry): ShapeCacheEntry(entry) { path = entry.path; } @@ -55,6 +54,7 @@ struct PathCacheEntry: public ShapeCacheEntry { } SkPath* path; + }; // PathCacheEntry /** diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 2187f24..972dd87 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -124,8 +124,15 @@ GLuint Program::buildShader(const char* source, GLenum type) { } void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, - const mat4& transformMatrix) { + const mat4& transformMatrix, bool offset) { mat4 t(projectionMatrix); + if (offset) { + // offset screenspace xy by an amount that compensates for typical precision issues + // in GPU hardware that tends to paint hor/vert lines in pixels shifted up and to the left. + // This offset value is based on an assumption that some hardware may use as little + // as 12.4 precision, so we offset by slightly more than 1/16. + t.translate(.375, .375, 0); + } t.multiply(transformMatrix); t.multiply(modelViewMatrix); diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index afc6f3d..764cb05 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -81,7 +81,7 @@ public: * transform matrices. */ void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, - const mat4& transformMatrix); + const mat4& transformMatrix, bool offset = false); /** * Sets the color associated with this shader. diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 0b6c7b5..d419e3e 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -39,8 +39,15 @@ const char* gVS_Header_Attributes = "attribute vec4 position;\n"; const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; +const char* gVS_Header_Attributes_AAParameters = + "attribute float vtxWidth;\n" + "attribute float vtxLength;\n"; +const char* gVS_Header_Uniforms_TextureTransform = + "uniform mat4 mainTextureTransform;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; +const char* gVS_Header_Uniforms_IsPoint = + "uniform mediump float pointSize;\n"; const char* gVS_Header_Uniforms_HasGradient[3] = { // Linear "uniform mat4 screenSpace;\n", @@ -51,11 +58,16 @@ const char* gVS_Header_Uniforms_HasGradient[3] = { }; const char* gVS_Header_Uniforms_HasBitmap = "uniform mat4 textureTransform;\n" - "uniform vec2 textureDimension;\n"; + "uniform mediump vec2 textureDimension;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; +const char* gVS_Header_Varyings_IsAA = + "varying float widthProportion;\n" + "varying float lengthProportion;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; +const char* gVS_Header_Varyings_PointHasBitmap = + "varying vec2 outPointBitmapTexCoords;\n"; const char* gVS_Header_Varyings_HasGradient[3] = { // Linear "varying vec2 linear;\n", @@ -68,6 +80,8 @@ const char* gVS_Main = "\nvoid main(void) {\n"; const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; +const char* gVS_Main_OutTransformedTexCoords = + " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n"; const char* gVS_Main_OutGradient[3] = { // Linear " linear = vec2((screenSpace * position).x, 0.5);\n", @@ -78,8 +92,15 @@ const char* gVS_Main_OutGradient[3] = { }; const char* gVS_Main_OutBitmapTexCoords = " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; +const char* gVS_Main_OutPointBitmapTexCoords = + " outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; +const char* gVS_Main_PointSize = + " gl_PointSize = pointSize;\n"; +const char* gVS_Main_AA = + " widthProportion = vtxWidth;\n" + " lengthProportion = vtxLength;\n"; const char* gVS_Footer = "}\n\n"; @@ -89,12 +110,24 @@ const char* gVS_Footer = const char* gFS_Header_Extension_FramebufferFetch = "#extension GL_NV_shader_framebuffer_fetch : enable\n\n"; +const char* gFS_Header_Extension_ExternalTexture = + "#extension GL_OES_EGL_image_external : require\n\n"; const char* gFS_Header = "precision mediump float;\n\n"; const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; +const char* gFS_Uniforms_AA = + "uniform float boundaryWidth;\n" + "uniform float inverseBoundaryWidth;\n" + "uniform float boundaryLength;\n" + "uniform float inverseBoundaryLength;\n"; +const char* gFS_Header_Uniforms_PointHasBitmap = + "uniform vec2 textureDimension;\n" + "uniform float pointSize;\n"; const char* gFS_Uniforms_TextureSampler = "uniform sampler2D sampler;\n"; +const char* gFS_Uniforms_ExternalTextureSampler = + "uniform samplerExternalOES sampler;\n"; const char* gFS_Uniforms_GradientSampler[3] = { // Linear "uniform sampler2D gradientSampler;\n", @@ -121,6 +154,10 @@ const char* gFS_Main = "\nvoid main(void) {\n" " lowp vec4 fragColor;\n"; +const char* gFS_Main_PointBitmapTexCoords = + " vec2 outBitmapTexCoords = outPointBitmapTexCoords + " + "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n"; + // Fast cases const char* gFS_Fast_SingleColor = "\nvoid main(void) {\n" @@ -154,6 +191,19 @@ const char* gFS_Fast_SingleModulateGradient = // General case const char* gFS_Main_FetchColor = " fragColor = color;\n"; +const char* gFS_Main_ModulateColor = + " fragColor *= color.a;\n"; +const char* gFS_Main_AccountForAA = + " if (widthProportion < boundaryWidth) {\n" + " fragColor *= (widthProportion * inverseBoundaryWidth);\n" + " } else if (widthProportion > (1.0 - boundaryWidth)) {\n" + " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n" + " }\n" + " if (lengthProportion < boundaryLength) {\n" + " fragColor *= (lengthProportion * inverseBoundaryLength);\n" + " } else if (lengthProportion > (1.0 - boundaryLength)) {\n" + " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n" + " }\n"; const char* gFS_Main_FetchTexture[2] = { // Don't modulate " fragColor = texture2D(sampler, outTexCoords);\n", @@ -336,38 +386,62 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { // Add attributes String8 shader(gVS_Header_Attributes); - if (description.hasTexture) { + if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Attributes_TexCoords); } + if (description.isAA) { + shader.append(gVS_Header_Attributes_AAParameters); + } // Uniforms shader.append(gVS_Header_Uniforms); + if (description.hasTextureTransform) { + shader.append(gVS_Header_Uniforms_TextureTransform); + } if (description.hasGradient) { shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } + if (description.isPoint) { + shader.append(gVS_Header_Uniforms_IsPoint); + } // Varyings - if (description.hasTexture) { + if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } + if (description.isAA) { + shader.append(gVS_Header_Varyings_IsAA); + } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Begin the shader shader.append(gVS_Main); { - if (description.hasTexture) { + if (description.hasTextureTransform) { + shader.append(gVS_Main_OutTransformedTexCoords); + } else if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Main_OutTexCoords); } + if (description.isAA) { + shader.append(gVS_Main_AA); + } if (description.hasGradient) { shader.append(gVS_Main_OutGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Main_OutBitmapTexCoords); + shader.append(description.isPoint ? + gVS_Main_OutPointBitmapTexCoords : + gVS_Main_OutBitmapTexCoords); + } + if (description.isPoint) { + shader.append(gVS_Main_PointSize); } // Output transformed position shader.append(gVS_Main_Position); @@ -388,23 +462,31 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } + if (description.hasExternalTexture) { + shader.append(gFS_Header_Extension_ExternalTexture); + } shader.append(gFS_Header); // Varyings - if (description.hasTexture) { + if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } + if (description.isAA) { + shader.append(gVS_Header_Varyings_IsAA); + } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); + shader.append(description.isPoint ? + gVS_Header_Varyings_PointHasBitmap : + gVS_Header_Varyings_HasBitmap); } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; - const bool singleColor = !description.hasTexture && + const bool singleColor = !description.hasTexture && !description.hasExternalTexture && !description.hasGradient && !description.hasBitmap; if (description.modulate || singleColor) { @@ -413,21 +495,30 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); + } else if (description.hasExternalTexture) { + shader.append(gFS_Uniforms_ExternalTextureSampler); + } + if (description.isAA) { + shader.append(gFS_Uniforms_AA); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } + if (description.hasBitmap && description.isPoint) { + shader.append(gFS_Header_Uniforms_PointHasBitmap); + } // Optimization for common cases - if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) { + if (!description.isAA && !blendFramebuffer && + description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; - const bool singleTexture = description.hasTexture && + const bool singleTexture = (description.hasTexture || description.hasExternalTexture) && !description.hasAlpha8Texture && noShader; const bool singleA8Texture = description.hasTexture && description.hasAlpha8Texture && noShader; - const bool singleGradient = !description.hasTexture && + const bool singleGradient = !description.hasTexture && !description.hasExternalTexture && description.hasGradient && !description.hasBitmap && description.gradientType == ProgramDescription::kGradientLinear; @@ -490,7 +581,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Begin the shader shader.append(gFS_Main); { // Stores the result in fragColor directly - if (description.hasTexture) { + if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchA8Texture[modulateOp]); @@ -503,16 +594,23 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchColor); } } + if (description.isAA) { + shader.append(gFS_Main_AccountForAA); + } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { + if (description.isPoint) { + shader.append(gFS_Main_PointBitmapTexCoords); + } if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); } } + bool applyModulate = false; // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; @@ -522,15 +620,21 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_BlendShadersGB); } shader.append(gFS_Main_BlendShaders_Modulate[op]); + applyModulate = true; } else { if (description.hasGradient) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_GradientShader_Modulate[op]); + applyModulate = true; } else if (description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_BitmapShader_Modulate[op]); + applyModulate = true; } } + if (description.modulate && applyModulate) { + shader.append(gFS_Main_ModulateColor); + } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); // Output the fragment diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index ead5b92..5c7197b 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -71,7 +71,14 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPT_SHIFT 11 #define PROGRAM_GRADIENT_TYPE_SHIFT 33 -#define PROGRAM_MODULATE 35 +#define PROGRAM_MODULATE_SHIFT 35 + +#define PROGRAM_IS_POINT_SHIFT 36 + +#define PROGRAM_HAS_AA_SHIFT 37 + +#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38 +#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39 /////////////////////////////////////////////////////////////////////////////// // Types @@ -109,6 +116,8 @@ struct ProgramDescription { // Texturing bool hasTexture; bool hasAlpha8Texture; + bool hasExternalTexture; + bool hasTextureTransform; // Modulate, this should only be set when setColor() return true bool modulate; @@ -117,6 +126,8 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; + bool isAA; + bool hasGradient; Gradient gradientType; @@ -135,6 +146,9 @@ struct ProgramDescription { SkXfermode::Mode framebufferMode; bool swapSrcDst; + bool isPoint; + float pointSize; + /** * Resets this description. All fields are reset back to the default * values they hold after building a new instance. @@ -142,6 +156,10 @@ struct ProgramDescription { void reset() { hasTexture = false; hasAlpha8Texture = false; + hasExternalTexture = false; + hasTextureTransform = false; + + isAA = false; modulate = false; @@ -162,6 +180,9 @@ struct ProgramDescription { framebufferMode = SkXfermode::kClear_Mode; swapSrcDst = false; + + isPoint = false; + pointSize = 0.0f; } /** @@ -223,7 +244,11 @@ struct ProgramDescription { } key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; - if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT; + if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT; + if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT; + if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT; + if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT; return key; } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 1aef99b..7c10518 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -27,8 +27,9 @@ // If turned on, layers drawn inside FBOs are optimized with regions #define RENDER_LAYERS_AS_REGIONS 1 -// If turned on, layers that map to a single rect are drawn as a rect -#define RENDER_LAYERS_RECT_AS_RECT 0 + +// If turned on, text is interpreted as glyphs instead of UTF-16 +#define RENDER_TEXT_AS_GLYPHS 1 /** * Debug level for app developers. diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index 4c626dd..b5cc29c 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -89,14 +89,17 @@ struct ShapeCacheEntry { join = SkPaint::kDefault_Join; cap = SkPaint::kDefault_Cap; style = SkPaint::kFill_Style; - miter = 4.0f; - strokeWidth = 1.0f; + float v = 4.0f; + miter = *(uint32_t*) &v; + v = 1.0f; + strokeWidth = *(uint32_t*) &v; + pathEffect = NULL; } ShapeCacheEntry(const ShapeCacheEntry& entry): shapeType(entry.shapeType), join(entry.join), cap(entry.cap), style(entry.style), miter(entry.miter), - strokeWidth(entry.strokeWidth) { + strokeWidth(entry.strokeWidth), pathEffect(entry.pathEffect) { } ShapeCacheEntry(ShapeType type, SkPaint* paint) { @@ -108,18 +111,19 @@ struct ShapeCacheEntry { v = paint->getStrokeWidth(); strokeWidth = *(uint32_t*) &v; style = paint->getStyle(); + pathEffect = paint->getPathEffect(); } virtual ~ShapeCacheEntry() { } - // shapeType must be checked in subclasses operator< ShapeType shapeType; SkPaint::Join join; SkPaint::Cap cap; SkPaint::Style style; uint32_t miter; uint32_t strokeWidth; + SkPathEffect* pathEffect; bool operator<(const ShapeCacheEntry& rhs) const { LTE_INT(shapeType) { @@ -128,7 +132,9 @@ struct ShapeCacheEntry { LTE_INT(style) { LTE_INT(miter) { LTE_INT(strokeWidth) { - return lessThan(rhs); + LTE_INT(pathEffect) { + return lessThan(rhs); + } } } } diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index d46686d..28dba13 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -73,7 +73,6 @@ struct ShadowText { text = str.string(); } - // TODO: Should take into account fake bold and text skew bool operator<(const ShadowText& rhs) const { LTE_INT(len) { LTE_INT(radius) { diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index bbf4d4a..38455dc 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -23,6 +23,18 @@ namespace uirenderer { /** * Simple structure to describe a vertex with a position and a texture. */ +struct Vertex { + float position[2]; + + static inline void set(Vertex* vertex, float x, float y) { + vertex[0].position[0] = x; + vertex[0].position[1] = y; + } +}; // struct Vertex + +/** + * Simple structure to describe a vertex with a position and a texture. + */ struct TextureVertex { float position[2]; float texture[2]; @@ -40,6 +52,41 @@ struct TextureVertex { } }; // struct TextureVertex +/** + * Simple structure to describe a vertex with a position and an alpha value. + */ +struct AlphaVertex : Vertex { + float alpha; + + static inline void set(AlphaVertex* vertex, float x, float y, float alpha) { + Vertex::set(vertex, x, y); + vertex[0].alpha = alpha; + } + + static inline void setColor(AlphaVertex* vertex, float alpha) { + vertex[0].alpha = alpha; + } +}; // struct AlphaVertex + +/** + * Simple structure to describe a vertex with a position and an alpha value. + */ +struct AAVertex : Vertex { + float width; + float length; + + static inline void set(AAVertex* vertex, float x, float y, float width, float length) { + Vertex::set(vertex, x, y); + vertex[0].width = width; + vertex[0].length = length; + } + + static inline void setColor(AAVertex* vertex, float width, float length) { + vertex[0].width = width; + vertex[0].length = length; + } +}; // struct AlphaVertex + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/utils/GenerationCache.h b/libs/hwui/utils/GenerationCache.h deleted file mode 100644 index 42e6d9b..0000000 --- a/libs/hwui/utils/GenerationCache.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010 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_HWUI_GENERATION_CACHE_H -#define ANDROID_HWUI_GENERATION_CACHE_H - -#include <utils/KeyedVector.h> -#include <utils/RefBase.h> - -namespace android { -namespace uirenderer { - -template<typename EntryKey, typename EntryValue> -class OnEntryRemoved { -public: - virtual ~OnEntryRemoved() { }; - virtual void operator()(EntryKey& key, EntryValue& value) = 0; -}; // class OnEntryRemoved - -template<typename EntryKey, typename EntryValue> -struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { - Entry() { } - Entry(const Entry<EntryKey, EntryValue>& e): - key(e.key), value(e.value), parent(e.parent), child(e.child) { } - Entry(sp<Entry<EntryKey, EntryValue> > e): - key(e->key), value(e->value), parent(e->parent), child(e->child) { } - - EntryKey key; - EntryValue value; - - sp<Entry<EntryKey, EntryValue> > parent; - sp<Entry<EntryKey, EntryValue> > child; -}; // struct Entry - -template<typename K, typename V> -class GenerationCache { -public: - GenerationCache(uint32_t maxCapacity); - virtual ~GenerationCache(); - - enum Capacity { - kUnlimitedCapacity, - }; - - void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); - - void clear(); - - bool contains(K key) const; - V get(K key); - K getKeyAt(uint32_t index) const; - bool put(K key, V value); - V remove(K key); - V removeOldest(); - V getValueAt(uint32_t index) const; - - uint32_t size() const; - - void addToCache(sp<Entry<K, V> > entry, K key, V value); - void attachToCache(sp<Entry<K, V> > entry); - void detachFromCache(sp<Entry<K, V> > entry); - - V removeAt(ssize_t index); - - KeyedVector<K, sp<Entry<K, V> > > mCache; - uint32_t mMaxCapacity; - - OnEntryRemoved<K, V>* mListener; - - sp<Entry<K, V> > mOldest; - sp<Entry<K, V> > mYoungest; -}; // class GenerationCache - -template<typename K, typename V> -GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { -}; - -template<typename K, typename V> -GenerationCache<K, V>::~GenerationCache() { - clear(); -}; - -template<typename K, typename V> -uint32_t GenerationCache<K, V>::size() const { - return mCache.size(); -} - -template<typename K, typename V> -void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) { - mListener = listener; -} - -template<typename K, typename V> -void GenerationCache<K, V>::clear() { - if (mListener) { - for (uint32_t i = 0; i < mCache.size(); i++) { - sp<Entry<K, V> > entry = mCache.valueAt(i); - if (mListener) { - (*mListener)(entry->key, entry->value); - } - } - } - mCache.clear(); - mYoungest.clear(); - mOldest.clear(); -} - -template<typename K, typename V> -bool GenerationCache<K, V>::contains(K key) const { - return mCache.indexOfKey(key) >= 0; -} - -template<typename K, typename V> -K GenerationCache<K, V>::getKeyAt(uint32_t index) const { - return mCache.keyAt(index); -} - -template<typename K, typename V> -V GenerationCache<K, V>::getValueAt(uint32_t index) const { - return mCache.valueAt(index)->value; -} - -template<typename K, typename V> -V GenerationCache<K, V>::get(K key) { - ssize_t index = mCache.indexOfKey(key); - if (index >= 0) { - sp<Entry<K, V> > entry = mCache.valueAt(index); - if (entry.get()) { - detachFromCache(entry); - attachToCache(entry); - return entry->value; - } - } - - return NULL; -} - -template<typename K, typename V> -bool GenerationCache<K, V>::put(K key, V value) { - if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { - removeOldest(); - } - - ssize_t index = mCache.indexOfKey(key); - if (index < 0) { - sp<Entry<K, V> > entry = new Entry<K, V>; - addToCache(entry, key, value); - return true; - } - - return false; -} - -template<typename K, typename V> -void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) { - entry->key = key; - entry->value = value; - mCache.add(key, entry); - attachToCache(entry); -} - -template<typename K, typename V> -V GenerationCache<K, V>::remove(K key) { - ssize_t index = mCache.indexOfKey(key); - if (index >= 0) { - return removeAt(index); - } - - return NULL; -} - -template<typename K, typename V> -V GenerationCache<K, V>::removeAt(ssize_t index) { - sp<Entry<K, V> > entry = mCache.valueAt(index); - if (mListener) { - (*mListener)(entry->key, entry->value); - } - mCache.removeItemsAt(index, 1); - detachFromCache(entry); - - return entry->value; -} - -template<typename K, typename V> -V GenerationCache<K, V>::removeOldest() { - if (mOldest.get()) { - ssize_t index = mCache.indexOfKey(mOldest->key); - if (index >= 0) { - return removeAt(index); - } - } - - return NULL; -} - -template<typename K, typename V> -void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { - if (!mYoungest.get()) { - mYoungest = mOldest = entry; - } else { - entry->parent = mYoungest; - mYoungest->child = entry; - mYoungest = entry; - } -} - -template<typename K, typename V> -void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) { - if (entry->parent.get()) { - entry->parent->child = entry->child; - } - - if (entry->child.get()) { - entry->child->parent = entry->parent; - } - - if (mOldest == entry) { - mOldest = entry->child; - } - - if (mYoungest == entry) { - mYoungest = entry->parent; - } - - entry->parent.clear(); - entry->child.clear(); -} - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_GENERATION_CACHE_H diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 0836887..9fabf8d 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -28,7 +28,6 @@ RSG_GENERATOR:=$(LOCAL_BUILT_MODULE) # slangdata_output_var_name := rs_runtime_lib_bc # LOCAL_MODULE := librslib_rt -# LOCAL_PRELINK_MODULE := false # LOCAL_MODULE_CLASS := STATIC_LIBRARIES # LOCAL_MODULE_TAGS := optional @@ -91,11 +90,15 @@ LOCAL_SRC_FILES:= \ rsContext.cpp \ rsDevice.cpp \ rsElement.cpp \ + rsFBOCache.cpp \ + rsFifoSocket.cpp \ rsFileA3D.cpp \ rsFont.cpp \ rsLocklessFifo.cpp \ rsObjectBase.cpp \ - rsMatrix.cpp \ + rsMatrix2x2.cpp \ + rsMatrix3x3.cpp \ + rsMatrix4x4.cpp \ rsMesh.cpp \ rsMutex.cpp \ rsProgram.cpp \ @@ -107,15 +110,27 @@ LOCAL_SRC_FILES:= \ rsScript.cpp \ rsScriptC.cpp \ rsScriptC_Lib.cpp \ - rsScriptC_LibCL.cpp \ rsScriptC_LibGL.cpp \ - rsShaderCache.cpp \ rsSignal.cpp \ rsStream.cpp \ rsThreadIO.cpp \ rsType.cpp \ - rsVertexArray.cpp - + driver/rsdAllocation.cpp \ + driver/rsdBcc.cpp \ + driver/rsdCore.cpp \ + driver/rsdFrameBuffer.cpp \ + driver/rsdGL.cpp \ + driver/rsdMesh.cpp \ + driver/rsdMeshObj.cpp \ + driver/rsdProgram.cpp \ + driver/rsdProgramRaster.cpp \ + driver/rsdProgramStore.cpp \ + driver/rsdRuntimeMath.cpp \ + driver/rsdRuntimeStubs.cpp \ + driver/rsdSampler.cpp \ + driver/rsdShader.cpp \ + driver/rsdShaderCache.cpp \ + driver/rsdVertexArray.cpp LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc @@ -134,24 +149,82 @@ include $(BUILD_SHARED_LIBRARY) # Now build a host version for serialization include $(CLEAR_VARS) +LOCAL_MODULE:= libRS +LOCAL_MODULE_TAGS := optional + +intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,HOST,) + +# Generate custom headers + +GEN := $(addprefix $(intermediates)/, \ + rsgApiStructs.h \ + rsgApiFuncDecl.h \ + ) + +$(GEN) : PRIVATE_PATH := $(LOCAL_PATH) +$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec +$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec +$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg + $(transform-generated-source) + +LOCAL_GENERATED_SOURCES += $(GEN) + +# Generate custom source files + +GEN := $(addprefix $(intermediates)/, \ + rsgApi.cpp \ + rsgApiReplay.cpp \ + ) + +$(GEN) : PRIVATE_PATH := $(LOCAL_PATH) +$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec +$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec +$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg + $(transform-generated-source) + +LOCAL_GENERATED_SOURCES += $(GEN) + LOCAL_CFLAGS += -Werror -Wall -Wno-unused-parameter -Wno-unused-variable LOCAL_CFLAGS += -DANDROID_RS_SERIALIZE +LOCAL_CFLAGS += -fPIC LOCAL_SRC_FILES:= \ + rsAdapter.cpp \ rsAllocation.cpp \ + rsAnimation.cpp \ rsComponent.cpp \ + rsContext.cpp \ + rsDevice.cpp \ rsElement.cpp \ + rsFBOCache.cpp \ + rsFifoSocket.cpp \ rsFileA3D.cpp \ + rsFont.cpp \ + rsLocklessFifo.cpp \ rsObjectBase.cpp \ + rsMatrix2x2.cpp \ + rsMatrix3x3.cpp \ + rsMatrix4x4.cpp \ rsMesh.cpp \ + rsMutex.cpp \ + rsProgram.cpp \ + rsProgramFragment.cpp \ + rsProgramStore.cpp \ + rsProgramRaster.cpp \ + rsProgramVertex.cpp \ + rsSampler.cpp \ + rsScript.cpp \ + rsScriptC.cpp \ + rsScriptC_Lib.cpp \ + rsScriptC_LibGL.cpp \ + rsSignal.cpp \ rsStream.cpp \ + rsThreadIO.cpp \ rsType.cpp LOCAL_STATIC_LIBRARIES := libcutils libutils LOCAL_LDLIBS := -lpthread -LOCAL_MODULE:= libRSserialize -LOCAL_MODULE_TAGS := optional include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index ffa9a8c..535f713 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -24,314 +24,9 @@ extern "C" { #endif -////////////////////////////////////////////////////// -// - -typedef void * RsAsyncVoidPtr; - -typedef void * RsAdapter1D; -typedef void * RsAdapter2D; -typedef void * RsAllocation; -typedef void * RsAnimation; -typedef void * RsContext; -typedef void * RsDevice; -typedef void * RsElement; -typedef void * RsFile; -typedef void * RsFont; -typedef void * RsSampler; -typedef void * RsScript; -typedef void * RsMesh; -typedef void * RsType; -typedef void * RsObjectBase; - -typedef void * RsProgram; -typedef void * RsProgramVertex; -typedef void * RsProgramFragment; -typedef void * RsProgramStore; -typedef void * RsProgramRaster; - -typedef void (* RsBitmapCallback_t)(void *); - -enum RsDeviceParam { - RS_DEVICE_PARAM_FORCE_SOFTWARE_GL, - RS_DEVICE_PARAM_COUNT -}; - -typedef struct { - uint32_t colorMin; - uint32_t colorPref; - uint32_t alphaMin; - uint32_t alphaPref; - uint32_t depthMin; - uint32_t depthPref; - uint32_t stencilMin; - uint32_t stencilPref; - uint32_t samplesMin; - uint32_t samplesPref; - float samplesQ; -} RsSurfaceConfig; - -RsDevice rsDeviceCreate(); -void rsDeviceDestroy(RsDevice); -void rsDeviceSetConfig(RsDevice, RsDeviceParam, int32_t value); - -RsContext rsContextCreate(RsDevice, uint32_t version); -RsContext rsContextCreateGL(RsDevice, uint32_t version, - RsSurfaceConfig sc, uint32_t dpi); -void rsContextDestroy(RsContext); - -enum RsMessageToClientType { - RS_MESSAGE_TO_CLIENT_NONE = 0, - RS_MESSAGE_TO_CLIENT_EXCEPTION = 1, - RS_MESSAGE_TO_CLIENT_RESIZE = 2, - RS_MESSAGE_TO_CLIENT_ERROR = 3, - RS_MESSAGE_TO_CLIENT_USER = 4 -}; - -RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait); -RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait); -void rsContextInitToClient(RsContext); -void rsContextDeinitToClient(RsContext); - -#define RS_MAX_TEXTURE 2 -#define RS_MAX_ATTRIBS 16 - - -enum RsAllocationUsageType { - RS_ALLOCATION_USAGE_SCRIPT = 0x0001, - RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, - RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, - RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, - - RS_ALLOCATION_USAGE_ALL = 0x000F -}; - -enum RsAllocationMipmapControl { - RS_ALLOCATION_MIPMAP_NONE = 0, - RS_ALLOCATION_MIPMAP_FULL = 1, - RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2 -}; - -enum RsAllocationCubemapFace { - RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1, - RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3, - RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4, - RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5 -}; - -enum RsDataType { - RS_TYPE_NONE, - RS_TYPE_FLOAT_16, - RS_TYPE_FLOAT_32, - RS_TYPE_FLOAT_64, - RS_TYPE_SIGNED_8, - RS_TYPE_SIGNED_16, - RS_TYPE_SIGNED_32, - RS_TYPE_SIGNED_64, - RS_TYPE_UNSIGNED_8, - RS_TYPE_UNSIGNED_16, - RS_TYPE_UNSIGNED_32, - RS_TYPE_UNSIGNED_64, - - RS_TYPE_BOOLEAN, - - RS_TYPE_UNSIGNED_5_6_5, - RS_TYPE_UNSIGNED_5_5_5_1, - RS_TYPE_UNSIGNED_4_4_4_4, - - RS_TYPE_MATRIX_4X4, - RS_TYPE_MATRIX_3X3, - RS_TYPE_MATRIX_2X2, - - RS_TYPE_ELEMENT = 1000, - RS_TYPE_TYPE, - RS_TYPE_ALLOCATION, - RS_TYPE_SAMPLER, - RS_TYPE_SCRIPT, - RS_TYPE_MESH, - RS_TYPE_PROGRAM_FRAGMENT, - RS_TYPE_PROGRAM_VERTEX, - RS_TYPE_PROGRAM_RASTER, - RS_TYPE_PROGRAM_STORE, -}; - -enum RsDataKind { - RS_KIND_USER, - - RS_KIND_PIXEL_L = 7, - RS_KIND_PIXEL_A, - RS_KIND_PIXEL_LA, - RS_KIND_PIXEL_RGB, - RS_KIND_PIXEL_RGBA, -}; - -enum RsSamplerParam { - RS_SAMPLER_MIN_FILTER, - RS_SAMPLER_MAG_FILTER, - RS_SAMPLER_WRAP_S, - RS_SAMPLER_WRAP_T, - RS_SAMPLER_WRAP_R, - RS_SAMPLER_ANISO -}; - -enum RsSamplerValue { - RS_SAMPLER_NEAREST, - RS_SAMPLER_LINEAR, - RS_SAMPLER_LINEAR_MIP_LINEAR, - RS_SAMPLER_WRAP, - RS_SAMPLER_CLAMP, - RS_SAMPLER_LINEAR_MIP_NEAREST, -}; - -enum RsTextureTarget { - RS_TEXTURE_2D, - RS_TEXTURE_CUBE -}; - -enum RsDimension { - RS_DIMENSION_X, - RS_DIMENSION_Y, - RS_DIMENSION_Z, - RS_DIMENSION_LOD, - RS_DIMENSION_FACE, - - RS_DIMENSION_ARRAY_0 = 100, - RS_DIMENSION_ARRAY_1, - RS_DIMENSION_ARRAY_2, - RS_DIMENSION_ARRAY_3, - RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3 -}; - -enum RsDepthFunc { - RS_DEPTH_FUNC_ALWAYS, - RS_DEPTH_FUNC_LESS, - RS_DEPTH_FUNC_LEQUAL, - RS_DEPTH_FUNC_GREATER, - RS_DEPTH_FUNC_GEQUAL, - RS_DEPTH_FUNC_EQUAL, - RS_DEPTH_FUNC_NOTEQUAL -}; - -enum RsBlendSrcFunc { - RS_BLEND_SRC_ZERO, // 0 - RS_BLEND_SRC_ONE, // 1 - RS_BLEND_SRC_DST_COLOR, // 2 - RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3 - RS_BLEND_SRC_SRC_ALPHA, // 4 - RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5 - RS_BLEND_SRC_DST_ALPHA, // 6 - RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7 - RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8 -}; - -enum RsBlendDstFunc { - RS_BLEND_DST_ZERO, // 0 - RS_BLEND_DST_ONE, // 1 - RS_BLEND_DST_SRC_COLOR, // 2 - RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3 - RS_BLEND_DST_SRC_ALPHA, // 4 - RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5 - RS_BLEND_DST_DST_ALPHA, // 6 - RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7 -}; - -enum RsTexEnvMode { - RS_TEX_ENV_MODE_NONE, - RS_TEX_ENV_MODE_REPLACE, - RS_TEX_ENV_MODE_MODULATE, - RS_TEX_ENV_MODE_DECAL -}; - -enum RsProgramParam { - RS_PROGRAM_PARAM_INPUT, - RS_PROGRAM_PARAM_OUTPUT, - RS_PROGRAM_PARAM_CONSTANT, - RS_PROGRAM_PARAM_TEXTURE_TYPE, -}; - -enum RsPrimitive { - RS_PRIMITIVE_POINT, - RS_PRIMITIVE_LINE, - RS_PRIMITIVE_LINE_STRIP, - RS_PRIMITIVE_TRIANGLE, - RS_PRIMITIVE_TRIANGLE_STRIP, - RS_PRIMITIVE_TRIANGLE_FAN -}; - -enum RsError { - RS_ERROR_NONE = 0, - RS_ERROR_BAD_SHADER = 1, - RS_ERROR_BAD_SCRIPT = 2, - RS_ERROR_BAD_VALUE = 3, - RS_ERROR_OUT_OF_MEMORY = 4, - RS_ERROR_DRIVER = 5, - - RS_ERROR_FATAL_UNKNOWN = 0x1000, - RS_ERROR_FATAL_DRIVER = 0x1001, - RS_ERROR_FATAL_PROGRAM_LINK = 0x1002 -}; - -enum RsAnimationInterpolation { - RS_ANIMATION_INTERPOLATION_STEP, - RS_ANIMATION_INTERPOLATION_LINEAR, - RS_ANIMATION_INTERPOLATION_BEZIER, - RS_ANIMATION_INTERPOLATION_CARDINAL, - RS_ANIMATION_INTERPOLATION_HERMITE, - RS_ANIMATION_INTERPOLATION_BSPLINE -}; - -enum RsAnimationEdge { - RS_ANIMATION_EDGE_UNDEFINED, - RS_ANIMATION_EDGE_CONSTANT, - RS_ANIMATION_EDGE_GRADIENT, - RS_ANIMATION_EDGE_CYCLE, - RS_ANIMATION_EDGE_OSCILLATE, - RS_ANIMATION_EDGE_CYLE_RELATIVE -}; - -enum RsA3DClassID { - RS_A3D_CLASS_ID_UNKNOWN, - RS_A3D_CLASS_ID_MESH, - RS_A3D_CLASS_ID_TYPE, - RS_A3D_CLASS_ID_ELEMENT, - RS_A3D_CLASS_ID_ALLOCATION, - RS_A3D_CLASS_ID_PROGRAM_VERTEX, - RS_A3D_CLASS_ID_PROGRAM_RASTER, - RS_A3D_CLASS_ID_PROGRAM_FRAGMENT, - RS_A3D_CLASS_ID_PROGRAM_STORE, - RS_A3D_CLASS_ID_SAMPLER, - RS_A3D_CLASS_ID_ANIMATION, - RS_A3D_CLASS_ID_ADAPTER_1D, - RS_A3D_CLASS_ID_ADAPTER_2D, - RS_A3D_CLASS_ID_SCRIPT_C -}; - -enum RsCullMode { - RS_CULL_BACK, - RS_CULL_FRONT, - RS_CULL_NONE -}; - -typedef struct { - RsA3DClassID classID; - const char* objectName; -} RsFileIndexEntry; - -// Script to Script -typedef struct { - uint32_t xStart; - uint32_t xEnd; - uint32_t yStart; - uint32_t yEnd; - uint32_t zStart; - uint32_t zEnd; - uint32_t arrayStart; - uint32_t arrayEnd; - -} RsScriptCall; +#include "RenderScriptDefines.h" +// // A3D loading and object update code. // Should only be called at object creation, not thread safe RsObjectBase rsaFileA3DGetEntryByIndex(RsContext, uint32_t idx, RsFile); @@ -354,25 +49,13 @@ void rsaTypeGetNativeData(RsContext, RsType, uint32_t *typeData, uint32_t typeDa void rsaElementGetNativeData(RsContext, RsElement, uint32_t *elemData, uint32_t elemDataSize); void rsaElementGetSubElements(RsContext, RsElement, uint32_t *ids, const char **names, uint32_t dataSize); -// Async commands for returning new IDS -RsType rsaTypeCreate(RsContext, RsElement, uint32_t dimX, uint32_t dimY, - uint32_t dimZ, bool mips, bool faces); -RsAllocation rsaAllocationCreateTyped(RsContext rsc, RsType vtype, - RsAllocationMipmapControl mips, - uint32_t usages); -RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages); -RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages); -#ifdef ANDROID_RS_SERIALIZE -#define NO_RS_FUNCS -#endif +RsDevice rsDeviceCreate(); +void rsDeviceDestroy(RsDevice dev); +void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value); +RsContext rsContextCreate(RsDevice dev, uint32_t version); +RsContext rsContextCreateGL(RsDevice dev, uint32_t version, RsSurfaceConfig sc, uint32_t dpi); -#ifndef NO_RS_FUNCS #include "rsgApiFuncDecl.h" -#endif #ifdef __cplusplus }; diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h new file mode 100644 index 0000000..ee9645c --- /dev/null +++ b/libs/rs/RenderScriptDefines.h @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2007 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 RENDER_SCRIPT_DEFINES_H +#define RENDER_SCRIPT_DEFINES_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////// +// + +typedef void * RsAsyncVoidPtr; + +typedef void * RsAdapter1D; +typedef void * RsAdapter2D; +typedef void * RsAllocation; +typedef void * RsAnimation; +typedef void * RsContext; +typedef void * RsDevice; +typedef void * RsElement; +typedef void * RsFile; +typedef void * RsFont; +typedef void * RsSampler; +typedef void * RsScript; +typedef void * RsMesh; +typedef void * RsType; +typedef void * RsObjectBase; + +typedef void * RsProgram; +typedef void * RsProgramVertex; +typedef void * RsProgramFragment; +typedef void * RsProgramStore; +typedef void * RsProgramRaster; + +typedef void * RsNativeWindow; + +typedef void (* RsBitmapCallback_t)(void *); + +typedef struct { + float m[16]; +} rs_matrix4x4; + +typedef struct { + float m[9]; +} rs_matrix3x3; + +typedef struct { + float m[4]; +} rs_matrix2x2; + +enum RsDeviceParam { + RS_DEVICE_PARAM_FORCE_SOFTWARE_GL, + RS_DEVICE_PARAM_COUNT +}; + +typedef struct { + uint32_t colorMin; + uint32_t colorPref; + uint32_t alphaMin; + uint32_t alphaPref; + uint32_t depthMin; + uint32_t depthPref; + uint32_t stencilMin; + uint32_t stencilPref; + uint32_t samplesMin; + uint32_t samplesPref; + float samplesQ; +} RsSurfaceConfig; + +enum RsMessageToClientType { + RS_MESSAGE_TO_CLIENT_NONE = 0, + RS_MESSAGE_TO_CLIENT_EXCEPTION = 1, + RS_MESSAGE_TO_CLIENT_RESIZE = 2, + RS_MESSAGE_TO_CLIENT_ERROR = 3, + RS_MESSAGE_TO_CLIENT_USER = 4 +}; + +enum RsAllocationUsageType { + RS_ALLOCATION_USAGE_SCRIPT = 0x0001, + RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE = 0x0002, + RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004, + RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008, + RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010, + + RS_ALLOCATION_USAGE_ALL = 0x000F +}; + +enum RsAllocationMipmapControl { + RS_ALLOCATION_MIPMAP_NONE = 0, + RS_ALLOCATION_MIPMAP_FULL = 1, + RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2 +}; + +enum RsAllocationCubemapFace { + RS_ALLOCATION_CUBMAP_FACE_POSITVE_X = 0, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_X = 1, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Y = 2, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Y = 3, + RS_ALLOCATION_CUBMAP_FACE_POSITVE_Z = 4, + RS_ALLOCATION_CUBMAP_FACE_NEGATIVE_Z = 5 +}; + +enum RsDataType { + RS_TYPE_NONE, + RS_TYPE_FLOAT_16, + RS_TYPE_FLOAT_32, + RS_TYPE_FLOAT_64, + RS_TYPE_SIGNED_8, + RS_TYPE_SIGNED_16, + RS_TYPE_SIGNED_32, + RS_TYPE_SIGNED_64, + RS_TYPE_UNSIGNED_8, + RS_TYPE_UNSIGNED_16, + RS_TYPE_UNSIGNED_32, + RS_TYPE_UNSIGNED_64, + + RS_TYPE_BOOLEAN, + + RS_TYPE_UNSIGNED_5_6_5, + RS_TYPE_UNSIGNED_5_5_5_1, + RS_TYPE_UNSIGNED_4_4_4_4, + + RS_TYPE_MATRIX_4X4, + RS_TYPE_MATRIX_3X3, + RS_TYPE_MATRIX_2X2, + + RS_TYPE_ELEMENT = 1000, + RS_TYPE_TYPE, + RS_TYPE_ALLOCATION, + RS_TYPE_SAMPLER, + RS_TYPE_SCRIPT, + RS_TYPE_MESH, + RS_TYPE_PROGRAM_FRAGMENT, + RS_TYPE_PROGRAM_VERTEX, + RS_TYPE_PROGRAM_RASTER, + RS_TYPE_PROGRAM_STORE, +}; + +enum RsDataKind { + RS_KIND_USER, + + RS_KIND_PIXEL_L = 7, + RS_KIND_PIXEL_A, + RS_KIND_PIXEL_LA, + RS_KIND_PIXEL_RGB, + RS_KIND_PIXEL_RGBA, + RS_KIND_PIXEL_DEPTH, +}; + +enum RsSamplerParam { + RS_SAMPLER_MIN_FILTER, + RS_SAMPLER_MAG_FILTER, + RS_SAMPLER_WRAP_S, + RS_SAMPLER_WRAP_T, + RS_SAMPLER_WRAP_R, + RS_SAMPLER_ANISO +}; + +enum RsSamplerValue { + RS_SAMPLER_NEAREST, + RS_SAMPLER_LINEAR, + RS_SAMPLER_LINEAR_MIP_LINEAR, + RS_SAMPLER_WRAP, + RS_SAMPLER_CLAMP, + RS_SAMPLER_LINEAR_MIP_NEAREST, +}; + +enum RsTextureTarget { + RS_TEXTURE_2D, + RS_TEXTURE_CUBE +}; + +enum RsDimension { + RS_DIMENSION_X, + RS_DIMENSION_Y, + RS_DIMENSION_Z, + RS_DIMENSION_LOD, + RS_DIMENSION_FACE, + + RS_DIMENSION_ARRAY_0 = 100, + RS_DIMENSION_ARRAY_1, + RS_DIMENSION_ARRAY_2, + RS_DIMENSION_ARRAY_3, + RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3 +}; + +enum RsDepthFunc { + RS_DEPTH_FUNC_ALWAYS, + RS_DEPTH_FUNC_LESS, + RS_DEPTH_FUNC_LEQUAL, + RS_DEPTH_FUNC_GREATER, + RS_DEPTH_FUNC_GEQUAL, + RS_DEPTH_FUNC_EQUAL, + RS_DEPTH_FUNC_NOTEQUAL +}; + +enum RsBlendSrcFunc { + RS_BLEND_SRC_ZERO, // 0 + RS_BLEND_SRC_ONE, // 1 + RS_BLEND_SRC_DST_COLOR, // 2 + RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3 + RS_BLEND_SRC_SRC_ALPHA, // 4 + RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5 + RS_BLEND_SRC_DST_ALPHA, // 6 + RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7 + RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8 +}; + +enum RsBlendDstFunc { + RS_BLEND_DST_ZERO, // 0 + RS_BLEND_DST_ONE, // 1 + RS_BLEND_DST_SRC_COLOR, // 2 + RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3 + RS_BLEND_DST_SRC_ALPHA, // 4 + RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5 + RS_BLEND_DST_DST_ALPHA, // 6 + RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7 +}; + +enum RsTexEnvMode { + RS_TEX_ENV_MODE_NONE, + RS_TEX_ENV_MODE_REPLACE, + RS_TEX_ENV_MODE_MODULATE, + RS_TEX_ENV_MODE_DECAL +}; + +enum RsProgramParam { + RS_PROGRAM_PARAM_INPUT, + RS_PROGRAM_PARAM_OUTPUT, + RS_PROGRAM_PARAM_CONSTANT, + RS_PROGRAM_PARAM_TEXTURE_TYPE, +}; + +enum RsPrimitive { + RS_PRIMITIVE_POINT, + RS_PRIMITIVE_LINE, + RS_PRIMITIVE_LINE_STRIP, + RS_PRIMITIVE_TRIANGLE, + RS_PRIMITIVE_TRIANGLE_STRIP, + RS_PRIMITIVE_TRIANGLE_FAN +}; + +enum RsError { + RS_ERROR_NONE = 0, + RS_ERROR_BAD_SHADER = 1, + RS_ERROR_BAD_SCRIPT = 2, + RS_ERROR_BAD_VALUE = 3, + RS_ERROR_OUT_OF_MEMORY = 4, + RS_ERROR_DRIVER = 5, + + RS_ERROR_FATAL_UNKNOWN = 0x1000, + RS_ERROR_FATAL_DRIVER = 0x1001, + RS_ERROR_FATAL_PROGRAM_LINK = 0x1002 +}; + +enum RsAnimationInterpolation { + RS_ANIMATION_INTERPOLATION_STEP, + RS_ANIMATION_INTERPOLATION_LINEAR, + RS_ANIMATION_INTERPOLATION_BEZIER, + RS_ANIMATION_INTERPOLATION_CARDINAL, + RS_ANIMATION_INTERPOLATION_HERMITE, + RS_ANIMATION_INTERPOLATION_BSPLINE +}; + +enum RsAnimationEdge { + RS_ANIMATION_EDGE_UNDEFINED, + RS_ANIMATION_EDGE_CONSTANT, + RS_ANIMATION_EDGE_GRADIENT, + RS_ANIMATION_EDGE_CYCLE, + RS_ANIMATION_EDGE_OSCILLATE, + RS_ANIMATION_EDGE_CYLE_RELATIVE +}; + +enum RsA3DClassID { + RS_A3D_CLASS_ID_UNKNOWN, + RS_A3D_CLASS_ID_MESH, + RS_A3D_CLASS_ID_TYPE, + RS_A3D_CLASS_ID_ELEMENT, + RS_A3D_CLASS_ID_ALLOCATION, + RS_A3D_CLASS_ID_PROGRAM_VERTEX, + RS_A3D_CLASS_ID_PROGRAM_RASTER, + RS_A3D_CLASS_ID_PROGRAM_FRAGMENT, + RS_A3D_CLASS_ID_PROGRAM_STORE, + RS_A3D_CLASS_ID_SAMPLER, + RS_A3D_CLASS_ID_ANIMATION, + RS_A3D_CLASS_ID_ADAPTER_1D, + RS_A3D_CLASS_ID_ADAPTER_2D, + RS_A3D_CLASS_ID_SCRIPT_C +}; + +enum RsCullMode { + RS_CULL_BACK, + RS_CULL_FRONT, + RS_CULL_NONE +}; + +typedef struct { + RsA3DClassID classID; + const char* objectName; +} RsFileIndexEntry; + +// Script to Script +typedef struct { + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; + +} RsScriptCall; + +#ifdef __cplusplus +}; +#endif + +#endif // RENDER_SCRIPT_DEFINES_H + + + + diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp new file mode 100644 index 0000000..2e13e9d --- /dev/null +++ b/libs/rs/driver/rsdAllocation.cpp @@ -0,0 +1,423 @@ +/* + * 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 "rsdCore.h" +#include "rsdBcc.h" +#include "rsdRuntime.h" +#include "rsdAllocation.h" + +#include "rsAllocation.h" + +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +using namespace android; +using namespace android::renderscript; + + + +const static GLenum gFaceOrder[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + + +GLenum rsdTypeToGLType(RsDataType t) { + switch (t) { + case RS_TYPE_UNSIGNED_5_6_5: return GL_UNSIGNED_SHORT_5_6_5; + case RS_TYPE_UNSIGNED_5_5_5_1: return GL_UNSIGNED_SHORT_5_5_5_1; + case RS_TYPE_UNSIGNED_4_4_4_4: return GL_UNSIGNED_SHORT_4_4_4_4; + + //case RS_TYPE_FLOAT_16: return GL_HALF_FLOAT; + case RS_TYPE_FLOAT_32: return GL_FLOAT; + case RS_TYPE_UNSIGNED_8: return GL_UNSIGNED_BYTE; + case RS_TYPE_UNSIGNED_16: return GL_UNSIGNED_SHORT; + case RS_TYPE_SIGNED_8: return GL_BYTE; + case RS_TYPE_SIGNED_16: return GL_SHORT; + default: break; + } + return 0; +} + +GLenum rsdKindToGLFormat(RsDataKind k) { + switch (k) { + case RS_KIND_PIXEL_L: return GL_LUMINANCE; + case RS_KIND_PIXEL_A: return GL_ALPHA; + case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA; + case RS_KIND_PIXEL_RGB: return GL_RGB; + case RS_KIND_PIXEL_RGBA: return GL_RGBA; + case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16; + default: break; + } + return 0; +} + + +static void Update2DTexture(const Allocation *alloc, const void *ptr, uint32_t xoff, uint32_t yoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + rsAssert(drv->textureID); + glBindTexture(drv->glTarget, drv->textureID); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + GLenum t = GL_TEXTURE_2D; + if (alloc->mHal.state.hasFaces) { + t = gFaceOrder[face]; + } + glTexSubImage2D(t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr); +} + + +static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + glBindTexture(drv->glTarget, drv->textureID); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + uint32_t faceCount = 1; + if (alloc->mHal.state.hasFaces) { + faceCount = 6; + } + + rsdGLCheckError(rsc, "Upload2DTexture 1 "); + for (uint32_t face = 0; face < faceCount; face ++) { + for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) { + const uint8_t *p = (const uint8_t *)drv->mallocPtr; + p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); + + GLenum t = GL_TEXTURE_2D; + if (alloc->mHal.state.hasFaces) { + t = gFaceOrder[face]; + } + + if (isFirstUpload) { + glTexImage2D(t, lod, drv->glFormat, + alloc->mHal.state.type->getLODDimX(lod), + alloc->mHal.state.type->getLODDimY(lod), + 0, drv->glFormat, drv->glType, p); + } else { + glTexSubImage2D(t, lod, 0, 0, + alloc->mHal.state.type->getLODDimX(lod), + alloc->mHal.state.type->getLODDimY(lod), + drv->glFormat, drv->glType, p); + } + } + } + + if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { + glGenerateMipmap(drv->glTarget); + } + rsdGLCheckError(rsc, "Upload2DTexture"); +} + +static void UploadToTexture(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->glType || !drv->glFormat) { + return; + } + + if (!alloc->getPtr()) { + return; + } + + bool isFirstUpload = false; + + if (!drv->textureID) { + glGenTextures(1, &drv->textureID); + isFirstUpload = true; + } + + Upload2DTexture(rsc, alloc, isFirstUpload); + + if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { + if (drv->mallocPtr) { + free(drv->mallocPtr); + drv->mallocPtr = NULL; + } + } + rsdGLCheckError(rsc, "UploadToTexture"); +} + +static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->glFormat) { + return; + } + + if (!drv->renderTargetID) { + glGenRenderbuffers(1, &drv->renderTargetID); + + if (!drv->renderTargetID) { + // This should generally not happen + LOGE("allocateRenderTarget failed to gen mRenderTargetID"); + rsc->dumpDebug(); + return; + } + glBindRenderbuffer(GL_RENDERBUFFER, drv->renderTargetID); + glRenderbufferStorage(GL_RENDERBUFFER, drv->glFormat, + alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY); + } + rsdGLCheckError(rsc, "AllocateRenderTarget"); +} + +static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + rsAssert(!alloc->mHal.state.type->getDimY()); + rsAssert(!alloc->mHal.state.type->getDimZ()); + + //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; + + if (!drv->bufferID) { + glGenBuffers(1, &drv->bufferID); + } + if (!drv->bufferID) { + LOGE("Upload to buffer object failed"); + drv->uploadDeferred = true; + return; + } + glBindBuffer(drv->glTarget, drv->bufferID); + glBufferData(drv->glTarget, alloc->mHal.state.type->getSizeBytes(), + drv->mallocPtr, GL_DYNAMIC_DRAW); + glBindBuffer(drv->glTarget, 0); + rsdGLCheckError(rsc, "UploadToBufferObject"); +} + +bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { + DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation)); + if (!drv) { + return false; + } + + void * ptr = malloc(alloc->mHal.state.type->getSizeBytes()); + if (!ptr) { + free(drv); + return false; + } + + drv->glTarget = GL_NONE; + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { + if (alloc->mHal.state.hasFaces) { + drv->glTarget = GL_TEXTURE_CUBE_MAP; + } else { + drv->glTarget = GL_TEXTURE_2D; + } + } else { + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { + drv->glTarget = GL_ARRAY_BUFFER; + } + } + + drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType()); + drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind()); + + + alloc->mHal.drvState.mallocPtr = ptr; + drv->mallocPtr = (uint8_t *)ptr; + alloc->mHal.drv = drv; + if (forceZero) { + memset(ptr, 0, alloc->mHal.state.type->getSizeBytes()); + } + + if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) { + drv->uploadDeferred = true; + } + return true; +} + +void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (drv->bufferID) { + // Causes a SW crash.... + //LOGV(" mBufferID %i", mBufferID); + //glDeleteBuffers(1, &mBufferID); + //mBufferID = 0; + } + if (drv->textureID) { + glDeleteTextures(1, &drv->textureID); + drv->textureID = 0; + } + if (drv->renderTargetID) { + glDeleteRenderbuffers(1, &drv->renderTargetID); + drv->renderTargetID = 0; + } + + if (drv->mallocPtr) { + free(drv->mallocPtr); + drv->mallocPtr = NULL; + } + free(drv); + alloc->mHal.drv = NULL; +} + +void rsdAllocationResize(const Context *rsc, const Allocation *alloc, + const Type *newType, bool zeroNew) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes()); + + // fixme + ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr; + + const uint32_t oldDimX = alloc->mHal.state.dimensionX; + const uint32_t dimX = newType->getDimX(); + + if (dimX > oldDimX) { + const Element *e = alloc->mHal.state.type->getElement(); + uint32_t stride = e->getSizeBytes(); + memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); + } +} + + + +void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc, + RsAllocationUsageType src) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + if (!drv->uploadDeferred) { + return; + } + + rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT); + + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { + UploadToTexture(rsc, alloc); + } else { + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { + AllocateRenderTarget(rsc, alloc); + } + } + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { + UploadToBufferObject(rsc, alloc); + } + + drv->uploadDeferred = false; +} + +void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + drv->uploadDeferred = true; +} + +void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t lod, uint32_t count, + const void *data, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes(); + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * xoff; + uint32_t size = count * eSize; + + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(data, count); + alloc->decRefs(ptr, count); + } + + memcpy(ptr, data, size); + drv->uploadDeferred = true; +} + +void rsdAllocationData2D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint32_t lineSize = eSize * w; + uint32_t destW = alloc->mHal.state.dimensionX; + + if (drv->mallocPtr) { + const uint8_t *src = static_cast<const uint8_t *>(data); + uint8_t *dst = drv->mallocPtr; + dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff); + + for (uint32_t line=yoff; line < (yoff+h); line++) { + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(src, w); + alloc->decRefs(dst, w); + } + memcpy(dst, src, lineSize); + src += lineSize; + dst += destW * eSize; + } + drv->uploadDeferred = true; + } else { + Update2DTexture(alloc, data, xoff, yoff, lod, face, w, h); + } +} + +void rsdAllocationData3D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { + +} + +void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc, + uint32_t x, + const void *data, uint32_t cIdx, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * x; + + const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + if (alloc->mHal.state.hasReferences) { + e->incRefs(data); + e->decRefs(ptr); + } + + memcpy(ptr, data, sizeBytes); + drv->uploadDeferred = true; +} + +void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc, + uint32_t x, uint32_t y, + const void *data, uint32_t cIdx, uint32_t sizeBytes) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint8_t * ptr = drv->mallocPtr; + ptr += eSize * (x + y * alloc->mHal.state.dimensionX); + + const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + if (alloc->mHal.state.hasReferences) { + e->incRefs(data); + e->decRefs(ptr); + } + + memcpy(ptr, data, sizeBytes); + drv->uploadDeferred = true; +} + + diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h new file mode 100644 index 0000000..d7385ce --- /dev/null +++ b/libs/rs/driver/rsdAllocation.h @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#ifndef RSD_ALLOCATION_H +#define RSD_ALLOCATION_H + +#include <rs_hal.h> +#include <rsRuntime.h> + +#include <GLES/gl.h> +#include <GLES2/gl2.h> + +struct DrvAllocation { + // Is this a legal structure to be used as a texture source. + // Initially this will require 1D or 2D and color data + uint32_t textureID; + + // Is this a legal structure to be used as a vertex source. + // Initially this will require 1D and x(yzw). Additional per element data + // is allowed. + uint32_t bufferID; + + // Is this a legal structure to be used as an FBO render target + uint32_t renderTargetID; + + uint8_t * mallocPtr; + + GLenum glTarget; + GLenum glType; + GLenum glFormat; + + + bool uploadDeferred; +}; + +GLenum rsdTypeToGLType(RsDataType t); +GLenum rsdKindToGLFormat(RsDataKind k); + + +bool rsdAllocationInit(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc, + bool forceZero); +void rsdAllocationDestroy(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +void rsdAllocationResize(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + const android::renderscript::Type *newType, bool zeroNew); +void rsdAllocationSyncAll(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + RsAllocationUsageType src); +void rsdAllocationMarkDirty(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +void rsdAllocationData1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t lod, uint32_t count, + const void *data, uint32_t sizeBytes); +void rsdAllocationData2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, + const void *data, uint32_t sizeBytes); +void rsdAllocationData3D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); + +void rsdAllocationElementData1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t x, + const void *data, uint32_t elementOff, uint32_t sizeBytes); +void rsdAllocationElementData2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t x, uint32_t y, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + + + + +#endif diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp new file mode 100644 index 0000000..8120864 --- /dev/null +++ b/libs/rs/driver/rsdBcc.cpp @@ -0,0 +1,553 @@ +/* + * 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 "rsdCore.h" +#include "rsdBcc.h" +#include "rsdRuntime.h" + +#include "rsContext.h" +#include "rsScriptC.h" + +#include "utils/Timers.h" +#include "utils/StopWatch.h" +extern "C" { +#include "libdex/ZipArchive.h" +} + + +using namespace android; +using namespace android::renderscript; + +struct DrvScript { + int (*mRoot)(); + void (*mInit)(); + + BCCScriptRef mBccScript; + + uint32_t mInvokeFunctionCount; + InvokeFunc_t *mInvokeFunctions; + uint32_t mFieldCount; + void ** mFieldAddress; + bool * mFieldIsObject; + + const uint8_t * mScriptText; + uint32_t mScriptTextLength; + + //uint32_t * mObjectSlots; + //uint32_t mObjectSlotCount; + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + +}; + + +static Script * setTLS(Script *sc) { + ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey); + rsAssert(tls); + Script *old = tls->mScript; + tls->mScript = sc; + return old; +} + + +// Input: cacheDir +// Input: resName +// Input: extName +// +// Note: cacheFile = resName + extName +// +// Output: Returns cachePath == cacheDir + cacheFile +static char *genCacheFileName(const char *cacheDir, + const char *resName, + const char *extName) { + char cachePath[512]; + char cacheFile[sizeof(cachePath)]; + const size_t kBufLen = sizeof(cachePath) - 1; + + cacheFile[0] = '\0'; + // Note: resName today is usually something like + // "/com.android.fountain:raw/fountain" + if (resName[0] != '/') { + // Get the absolute path of the raw/***.bc file. + + // Generate the absolute path. This doesn't do everything it + // should, e.g. if resName is "./out/whatever" it doesn't crunch + // the leading "./" out because this if-block is not triggered, + // but it'll make do. + // + if (getcwd(cacheFile, kBufLen) == NULL) { + LOGE("Can't get CWD while opening raw/***.bc file\n"); + return NULL; + } + // Append "/" at the end of cacheFile so far. + strncat(cacheFile, "/", kBufLen); + } + + // cacheFile = resName + extName + // + strncat(cacheFile, resName, kBufLen); + if (extName != NULL) { + // TODO(srhines): strncat() is a bit dangerous + strncat(cacheFile, extName, kBufLen); + } + + // Turn the path into a flat filename by replacing + // any slashes after the first one with '@' characters. + char *cp = cacheFile + 1; + while (*cp != '\0') { + if (*cp == '/') { + *cp = '@'; + } + cp++; + } + + // Tack on the file name for the actual cache file path. + strncpy(cachePath, cacheDir, kBufLen); + strncat(cachePath, cacheFile, kBufLen); + + LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); + return strdup(cachePath); +} + +bool rsdScriptInit(const Context *rsc, + ScriptC *script, + char const *resName, + char const *cacheDir, + uint8_t const *bitcode, + size_t bitcodeSize, + uint32_t flags) { + //LOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc); + + pthread_mutex_lock(&rsdgInitMutex); + char *cachePath = NULL; + uint32_t objectSlotCount = 0; + + DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript)); + if (drv == NULL) { + goto error; + } + script->mHal.drv = drv; + + drv->mBccScript = bccCreateScript(); + script->mHal.info.isThreadable = true; + drv->mScriptText = bitcode; + drv->mScriptTextLength = bitcodeSize; + + //LOGE("mBccScript %p", script->mBccScript); + + if (bccRegisterSymbolCallback(drv->mBccScript, &rsdLookupRuntimeStub, script) != 0) { + LOGE("bcc: FAILS to register symbol callback"); + goto error; + } + + if (bccReadBC(drv->mBccScript, + resName, + (char const *)drv->mScriptText, + drv->mScriptTextLength, 0) != 0) { + LOGE("bcc: FAILS to read bitcode"); + goto error; + } + +#if 1 + if (bccLinkFile(drv->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { + LOGE("bcc: FAILS to link bitcode"); + goto error; + } +#endif + cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); + + if (bccPrepareExecutable(drv->mBccScript, cachePath, 0) != 0) { + LOGE("bcc: FAILS to prepare executable"); + goto error; + } + + free(cachePath); + + drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root")); + drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init")); + + drv->mInvokeFunctionCount = bccGetExportFuncCount(drv->mBccScript); + if (drv->mInvokeFunctionCount <= 0) + drv->mInvokeFunctions = NULL; + else { + drv->mInvokeFunctions = (InvokeFunc_t*) calloc(drv->mInvokeFunctionCount, sizeof(InvokeFunc_t)); + bccGetExportFuncList(drv->mBccScript, drv->mInvokeFunctionCount, (void **) drv->mInvokeFunctions); + } + + drv->mFieldCount = bccGetExportVarCount(drv->mBccScript); + if (drv->mFieldCount <= 0) { + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + } else { + drv->mFieldAddress = (void **) calloc(drv->mFieldCount, sizeof(void *)); + drv->mFieldIsObject = (bool *) calloc(drv->mFieldCount, sizeof(bool)); + bccGetExportVarList(drv->mBccScript, drv->mFieldCount, (void **) drv->mFieldAddress); + } + + objectSlotCount = bccGetObjectSlotCount(drv->mBccScript); + if (objectSlotCount) { + uint32_t * slots = new uint32_t[objectSlotCount]; + bccGetObjectSlotList(drv->mBccScript, objectSlotCount, slots); + for (uint32_t ct=0; ct < objectSlotCount; ct++) { + drv->mFieldIsObject[slots[ct]] = true; + } + delete [] slots; + } + + uint32_t mPragmaCount; + const char ** mPragmaKeys; + const char ** mPragmaValues; + + const static int pragmaMax = 16; + drv->mPragmaCount = bccGetPragmaCount(drv->mBccScript); + if (drv->mPragmaCount <= 0) { + drv->mPragmaKeys = NULL; + drv->mPragmaValues = NULL; + } else { + drv->mPragmaKeys = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + drv->mPragmaValues = (const char **) calloc(drv->mFieldCount, sizeof(const char *)); + bccGetPragmaList(drv->mBccScript, drv->mPragmaCount, drv->mPragmaKeys, drv->mPragmaValues); + } + + + + // Copy info over to runtime + script->mHal.info.exportedFunctionCount = drv->mInvokeFunctionCount; + script->mHal.info.exportedVariableCount = drv->mFieldCount; + script->mHal.info.exportedPragmaCount = drv->mPragmaCount; + script->mHal.info.exportedPragmaKeyList = drv->mPragmaKeys; + script->mHal.info.exportedPragmaValueList = drv->mPragmaValues; + script->mHal.info.root = drv->mRoot; + + + pthread_mutex_unlock(&rsdgInitMutex); + return true; + +error: + + pthread_mutex_unlock(&rsdgInitMutex); + free(drv); + return false; + +} + +typedef struct { + Context *rsc; + Script *script; + const Allocation * ain; + Allocation * aout; + const void * usr; + + uint32_t mSliceSize; + volatile int mSliceNum; + + const uint8_t *ptrIn; + uint32_t eStrideIn; + uint8_t *ptrOut; + uint32_t eStrideOut; + + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; + + uint32_t dimX; + uint32_t dimY; + uint32_t dimZ; + uint32_t dimArray; +} MTLaunchStruct; +typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); + +static void wc_xy(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize; + uint32_t yEnd = yStart + mtls->mSliceSize; + yEnd = rsMin(yEnd, mtls->yEnd); + if (yEnd <= yStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + for (uint32_t y = yStart; y < yEnd; y++) { + uint32_t offset = mtls->dimX * y; + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset); + + for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } + } +} + +static void wc_x(void *usr, uint32_t idx) { + MTLaunchStruct *mtls = (MTLaunchStruct *)usr; + + while (1) { + uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); + uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize; + uint32_t xEnd = xStart + mtls->mSliceSize; + xEnd = rsMin(xEnd, mtls->xEnd); + if (xEnd <= xStart) { + return; + } + + //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); + //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); + uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart); + const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart); + for (uint32_t x = xStart; x < xEnd; x++) { + ((rs_t)mtls->script->mHal.info.root) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0); + xPtrIn += mtls->eStrideIn; + xPtrOut += mtls->eStrideOut; + } + } +} + +void rsdScriptInvokeForEach(const Context *rsc, + Script *s, + const Allocation * ain, + Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc) { + + RsdHal * dc = (RsdHal *)rsc->mHal.drv; + + MTLaunchStruct mtls; + memset(&mtls, 0, sizeof(mtls)); + + if (ain) { + mtls.dimX = ain->getType()->getDimX(); + mtls.dimY = ain->getType()->getDimY(); + mtls.dimZ = ain->getType()->getDimZ(); + //mtls.dimArray = ain->getType()->getDimArray(); + } else if (aout) { + mtls.dimX = aout->getType()->getDimX(); + mtls.dimY = aout->getType()->getDimY(); + mtls.dimZ = aout->getType()->getDimZ(); + //mtls.dimArray = aout->getType()->getDimArray(); + } else { + rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); + return; + } + + if (!sc || (sc->xEnd == 0)) { + mtls.xEnd = mtls.dimX; + } else { + rsAssert(sc->xStart < mtls.dimX); + rsAssert(sc->xEnd <= mtls.dimX); + rsAssert(sc->xStart < sc->xEnd); + mtls.xStart = rsMin(mtls.dimX, sc->xStart); + mtls.xEnd = rsMin(mtls.dimX, sc->xEnd); + if (mtls.xStart >= mtls.xEnd) return; + } + + if (!sc || (sc->yEnd == 0)) { + mtls.yEnd = mtls.dimY; + } else { + rsAssert(sc->yStart < mtls.dimY); + rsAssert(sc->yEnd <= mtls.dimY); + rsAssert(sc->yStart < sc->yEnd); + mtls.yStart = rsMin(mtls.dimY, sc->yStart); + mtls.yEnd = rsMin(mtls.dimY, sc->yEnd); + if (mtls.yStart >= mtls.yEnd) return; + } + + mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd); + mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd); + mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd); + mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd); + + rsAssert(!ain || (ain->getType()->getDimZ() == 0)); + + Context *mrsc = (Context *)rsc; + Script * oldTLS = setTLS(s); + + mtls.rsc = mrsc; + mtls.ain = ain; + mtls.aout = aout; + mtls.script = s; + mtls.usr = usr; + mtls.mSliceSize = 10; + mtls.mSliceNum = 0; + + mtls.ptrIn = NULL; + mtls.eStrideIn = 0; + if (ain) { + mtls.ptrIn = (const uint8_t *)ain->getPtr(); + mtls.eStrideIn = ain->getType()->getElementSizeBytes(); + } + + mtls.ptrOut = NULL; + mtls.eStrideOut = 0; + if (aout) { + mtls.ptrOut = (uint8_t *)aout->getPtr(); + mtls.eStrideOut = aout->getType()->getElementSizeBytes(); + } + + if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable) { + if (mtls.dimY > 1) { + rsdLaunchThreads(mrsc, wc_xy, &mtls); + } else { + rsdLaunchThreads(mrsc, wc_x, &mtls); + } + + //LOGE("launch 1"); + } else { + //LOGE("launch 3"); + for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { + for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { + for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { + uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar + + mtls.dimX * mtls.dimY * z + + mtls.dimX * y; + uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset); + const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset); + + for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) { + ((rs_t)s->mHal.info.root) (xPtrIn, xPtrOut, usr, x, y, z, ar); + xPtrIn += mtls.eStrideIn; + xPtrOut += mtls.eStrideOut; + } + } + } + } + } + + setTLS(oldTLS); +} + + +int rsdScriptInvokeRoot(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + Script * oldTLS = setTLS(script); + int ret = drv->mRoot(); + setTLS(oldTLS); + + return ret; +} + +void rsdScriptInvokeInit(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mInit) { + drv->mInit(); + } +} + + +void rsdScriptInvokeFunction(const Context *dc, Script *script, + uint32_t slot, + const void *params, + size_t paramLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //LOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength); + + Script * oldTLS = setTLS(script); + ((void (*)(const void *, uint32_t)) + drv->mInvokeFunctions[slot])(params, paramLength); + setTLS(oldTLS); +} + +void rsdScriptSetGlobalVar(const Context *dc, const Script *script, + uint32_t slot, void *data, size_t dataLength) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, data, dataLength); +} + +void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(!script->mFieldIsObject[slot]); + //LOGE("setGlobalBind %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + memcpy(destPtr, &data, sizeof(void *)); +} + +void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + //rsAssert(script->mFieldIsObject[slot]); + //LOGE("setGlobalObj %p %p %i %p", dc, script, slot, data); + + int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot]; + if (!destPtr) { + //LOGV("Calling setVar on slot = %i which is null", slot); + return; + } + + rsrSetObject(dc, script, (ObjectBase **)destPtr, data); +} + +void rsdScriptDestroy(const Context *dc, Script *script) { + DrvScript *drv = (DrvScript *)script->mHal.drv; + + if (drv->mFieldAddress) { + for (size_t ct=0; ct < drv->mFieldCount; ct++) { + if (drv->mFieldIsObject[ct]) { + // The field address can be NULL if the script-side has + // optimized the corresponding global variable away. + if (drv->mFieldAddress[ct]) { + rsrClearObject(dc, script, (ObjectBase **)drv->mFieldAddress[ct]); + } + } + } + delete [] drv->mFieldAddress; + delete [] drv->mFieldIsObject; + drv->mFieldAddress = NULL; + drv->mFieldIsObject = NULL; + drv->mFieldCount = 0; + } + + if (drv->mInvokeFunctions) { + delete [] drv->mInvokeFunctions; + drv->mInvokeFunctions = NULL; + drv->mInvokeFunctionCount = 0; + } + free(drv); + script->mHal.drv = NULL; + +} + + diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h new file mode 100644 index 0000000..62b50f4 --- /dev/null +++ b/libs/rs/driver/rsdBcc.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef RSD_BCC_H +#define RSD_BCC_H + +#include <rs_hal.h> +#include <rsRuntime.h> + + +bool rsdScriptInit(const android::renderscript::Context *, android::renderscript::ScriptC *, + char const *resName, char const *cacheDir, + uint8_t const *bitcode, size_t bitcodeSize, uint32_t flags); +void rsdScriptInvokeFunction(const android::renderscript::Context *dc, + android::renderscript::Script *script, + uint32_t slot, + const void *params, + size_t paramLength); + +void rsdScriptInvokeForEach(const android::renderscript::Context *rsc, + android::renderscript::Script *s, + const android::renderscript::Allocation * ain, + android::renderscript::Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc); + +int rsdScriptInvokeRoot(const android::renderscript::Context *dc, + android::renderscript::Script *script); +void rsdScriptInvokeInit(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +void rsdScriptSetGlobalVar(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data, size_t dataLen); +void rsdScriptSetGlobalBind(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data); +void rsdScriptSetGlobalObj(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, android::renderscript::ObjectBase *data); + +void rsdScriptSetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptGetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, + void *data, + size_t dataLength); +void rsdScriptDestroy(const android::renderscript::Context *dc, + android::renderscript::Script *script); + + +#endif diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp new file mode 100644 index 0000000..01cc369 --- /dev/null +++ b/libs/rs/driver/rsdCore.cpp @@ -0,0 +1,287 @@ +/* + * 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 "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdBcc.h" +#include "rsdGL.h" +#include "rsdProgramStore.h" +#include "rsdProgramRaster.h" +#include "rsdProgramVertex.h" +#include "rsdProgramFragment.h" +#include "rsdMesh.h" +#include "rsdSampler.h" +#include "rsdFrameBuffer.h" + +#include <malloc.h> +#include "rsContext.h" + +#include <sys/types.h> +#include <sys/resource.h> +#include <sched.h> +#include <cutils/properties.h> +#include <cutils/sched_policy.h> +#include <sys/syscall.h> +#include <string.h> +#include <bcc/bcc.h> + +using namespace android; +using namespace android::renderscript; + +static void Shutdown(Context *rsc); +static void SetPriority(const Context *rsc, int32_t priority); + +static RsdHalFunctions FunctionTable = { + rsdGLInit, + rsdGLShutdown, + rsdGLSetSurface, + rsdGLSwap, + + Shutdown, + NULL, + SetPriority, + { + rsdScriptInit, + rsdScriptInvokeFunction, + rsdScriptInvokeRoot, + rsdScriptInvokeForEach, + rsdScriptInvokeInit, + rsdScriptSetGlobalVar, + rsdScriptSetGlobalBind, + rsdScriptSetGlobalObj, + rsdScriptDestroy + }, + + { + rsdAllocationInit, + rsdAllocationDestroy, + rsdAllocationResize, + rsdAllocationSyncAll, + rsdAllocationMarkDirty, + rsdAllocationData1D, + rsdAllocationData2D, + rsdAllocationData3D, + rsdAllocationElementData1D, + rsdAllocationElementData2D + }, + + + { + rsdProgramStoreInit, + rsdProgramStoreSetActive, + rsdProgramStoreDestroy + }, + + { + rsdProgramRasterInit, + rsdProgramRasterSetActive, + rsdProgramRasterDestroy + }, + + { + rsdProgramVertexInit, + rsdProgramVertexSetActive, + rsdProgramVertexDestroy + }, + + { + rsdProgramFragmentInit, + rsdProgramFragmentSetActive, + rsdProgramFragmentDestroy + }, + + { + rsdMeshInit, + rsdMeshDraw, + rsdMeshDestroy + }, + + { + rsdSamplerInit, + rsdSamplerDestroy + }, + + { + rsdFrameBufferInit, + rsdFrameBufferSetActive, + rsdFrameBufferDestroy + }, + +}; + +pthread_key_t rsdgThreadTLSKey = 0; +uint32_t rsdgThreadTLSKeyCount = 0; +pthread_mutex_t rsdgInitMutex = PTHREAD_MUTEX_INITIALIZER; + + +static void * HelperThreadProc(void *vrsc) { + Context *rsc = static_cast<Context *>(vrsc); + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + + uint32_t idx = (uint32_t)android_atomic_inc(&dc->mWorkers.mLaunchCount); + + //LOGV("RS helperThread starting %p idx=%i", rsc, idx); + + dc->mWorkers.mLaunchSignals[idx].init(); + dc->mWorkers.mNativeThreadId[idx] = gettid(); + + int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct); + if (status) { + LOGE("pthread_setspecific %i", status); + } + +#if 0 + typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; + cpu_set_t cpuset; + memset(&cpuset, 0, sizeof(cpuset)); + cpuset.bits[idx / 64] |= 1ULL << (idx % 64); + int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], + sizeof(cpuset), &cpuset); + LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); +#endif + + while (!dc->mExit) { + dc->mWorkers.mLaunchSignals[idx].wait(); + if (dc->mWorkers.mLaunchCallback) { + dc->mWorkers.mLaunchCallback(dc->mWorkers.mLaunchData, idx); + } + android_atomic_dec(&dc->mWorkers.mRunningCount); + dc->mWorkers.mCompleteSignal.set(); + } + + //LOGV("RS helperThread exited %p idx=%i", rsc, idx); + return NULL; +} + +void rsdLaunchThreads(Context *rsc, WorkerCallback_t cbk, void *data) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->mWorkers.mLaunchData = data; + dc->mWorkers.mLaunchCallback = cbk; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + dc->mWorkers.mCompleteSignal.wait(); + } +} + +bool rsdHalInit(Context *rsc, uint32_t version_major, uint32_t version_minor) { + rsc->mHal.funcs = FunctionTable; + + RsdHal *dc = (RsdHal *)calloc(1, sizeof(RsdHal)); + if (!dc) { + LOGE("Calloc for driver hal failed."); + return false; + } + rsc->mHal.drv = dc; + + pthread_mutex_lock(&rsdgInitMutex); + if (!rsdgThreadTLSKeyCount) { + int status = pthread_key_create(&rsdgThreadTLSKey, NULL); + if (status) { + LOGE("Failed to init thread tls key."); + pthread_mutex_unlock(&rsdgInitMutex); + return false; + } + } + rsdgThreadTLSKeyCount++; + pthread_mutex_unlock(&rsdgInitMutex); + + dc->mTlsStruct.mContext = rsc; + dc->mTlsStruct.mScript = NULL; + int status = pthread_setspecific(rsdgThreadTLSKey, &dc->mTlsStruct); + if (status) { + LOGE("pthread_setspecific %i", status); + } + + + int cpu = sysconf(_SC_NPROCESSORS_ONLN); + LOGV("RS Launching thread(s), reported CPU count %i", cpu); + if (cpu < 2) cpu = 0; + + dc->mWorkers.mCount = (uint32_t)cpu; + dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t)); + dc->mWorkers.mNativeThreadId = (pid_t *) calloc(dc->mWorkers.mCount, sizeof(pid_t)); + dc->mWorkers.mLaunchSignals = new Signal[dc->mWorkers.mCount]; + dc->mWorkers.mLaunchCallback = NULL; + + dc->mWorkers.mCompleteSignal.init(); + + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + android_atomic_release_store(0, &dc->mWorkers.mLaunchCount); + + pthread_attr_t threadAttr; + status = pthread_attr_init(&threadAttr); + if (status) { + LOGE("Failed to init thread attribute."); + return false; + } + + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_create(&dc->mWorkers.mThreadId[ct], &threadAttr, HelperThreadProc, rsc); + if (status) { + dc->mWorkers.mCount = ct; + LOGE("Created fewer than expected number of RS threads."); + break; + } + } + while (android_atomic_acquire_load(&dc->mWorkers.mRunningCount) != 0) { + usleep(100); + } + + pthread_attr_destroy(&threadAttr); + return true; +} + + +void SetPriority(const Context *rsc, int32_t priority) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { + setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority); + } +} + +void Shutdown(Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->mExit = true; + dc->mWorkers.mLaunchData = NULL; + dc->mWorkers.mLaunchCallback = NULL; + android_atomic_release_store(dc->mWorkers.mCount, &dc->mWorkers.mRunningCount); + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + dc->mWorkers.mLaunchSignals[ct].set(); + } + int status; + void *res; + for (uint32_t ct = 0; ct < dc->mWorkers.mCount; ct++) { + status = pthread_join(dc->mWorkers.mThreadId[ct], &res); + } + rsAssert(android_atomic_acquire_load(&dc->mWorkers.mRunningCount) == 0); + + // Global structure cleanup. + pthread_mutex_lock(&rsdgInitMutex); + --rsdgThreadTLSKeyCount; + if (!rsdgThreadTLSKeyCount) { + pthread_key_delete(rsdgThreadTLSKey); + } + pthread_mutex_unlock(&rsdgInitMutex); + +} + + diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h new file mode 100644 index 0000000..f393b60 --- /dev/null +++ b/libs/rs/driver/rsdCore.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef RSD_CORE_H +#define RSD_CORE_H + +#include <rs_hal.h> + +#include "rsMutex.h" +#include "rsSignal.h" + +#include "rsdGL.h" + +typedef void (* InvokeFunc_t)(void); +typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); + +typedef struct RsdSymbolTableRec { + const char * mName; + void * mPtr; + bool threadable; +} RsdSymbolTable; + +typedef struct ScriptTLSStructRec { + android::renderscript::Context * mContext; + android::renderscript::Script * mScript; +} ScriptTLSStruct; + +typedef struct RsdHalRec { + uint32_t version_major; + uint32_t version_minor; + + struct Workers { + volatile int mRunningCount; + volatile int mLaunchCount; + uint32_t mCount; + pthread_t *mThreadId; + pid_t *mNativeThreadId; + android::renderscript::Signal mCompleteSignal; + + android::renderscript::Signal *mLaunchSignals; + WorkerCallback_t mLaunchCallback; + void *mLaunchData; + }; + Workers mWorkers; + bool mExit; + + ScriptTLSStruct mTlsStruct; + + RsdGL gl; +} RsdHal; + +extern pthread_key_t rsdgThreadTLSKey; +extern uint32_t rsdgThreadTLSKeyCount; +extern pthread_mutex_t rsdgInitMutex; + + +void rsdLaunchThreads(android::renderscript::Context *rsc, WorkerCallback_t cbk, void *data); + +#endif + diff --git a/libs/rs/driver/rsdFrameBuffer.cpp b/libs/rs/driver/rsdFrameBuffer.cpp new file mode 100644 index 0000000..ce72b5d --- /dev/null +++ b/libs/rs/driver/rsdFrameBuffer.cpp @@ -0,0 +1,161 @@ +/* + * 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 "rsdCore.h" +#include "rsdFrameBuffer.h" +#include "rsdAllocation.h" + +#include "rsContext.h" +#include "rsFBOCache.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +struct DrvFrameBuffer { + GLuint mFBOId; +}; + +void checkError(const Context *rsc) { + GLenum status; + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + switch (status) { + case GL_FRAMEBUFFER_COMPLETE: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + rsc->setError(RS_ERROR_BAD_VALUE, + "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED"); + break; + } +} + + +void setDepthAttachment(const Context *rsc, const FBOCache *fb) { + if (fb->mHal.state.depthTarget.get() != NULL) { + DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv; + + if (drv->textureID) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, drv->textureID, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, drv->renderTargetID); + } + } else { + // Reset last attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + } +} + +void setColorAttachment(const Context *rsc, const FBOCache *fb) { + // Now attach color targets + for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) { + uint32_t texID = 0; + if (fb->mHal.state.colorTargets[i].get() != NULL) { + DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv; + + if (drv->textureID) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, drv->textureID, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_RENDERBUFFER, drv->renderTargetID); + } + } else { + // Reset last attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_RENDERBUFFER, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, 0, 0); + } + } +} + +bool renderToFramebuffer(const FBOCache *fb) { + if (fb->mHal.state.depthTarget.get() != NULL) { + return false; + } + + for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) { + if (fb->mHal.state.colorTargets[i].get() != NULL) { + return false; + } + } + return true; +} + + +bool rsdFrameBufferInit(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)calloc(1, sizeof(DrvFrameBuffer)); + if (drv == NULL) { + return false; + } + fb->mHal.drv = drv; + drv->mFBOId = 0; + + return true; +} + +void rsdFrameBufferSetActive(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv; + + bool framebuffer = renderToFramebuffer(fb); + if (!framebuffer) { + if(drv->mFBOId == 0) { + glGenFramebuffers(1, &drv->mFBOId); + } + glBindFramebuffer(GL_FRAMEBUFFER, drv->mFBOId); + + setDepthAttachment(rsc, fb); + setColorAttachment(rsc, fb); + + glViewport(0, 0, fb->mHal.state.colorTargets[0]->getType()->getDimX(), + fb->mHal.state.colorTargets[0]->getType()->getDimY()); + + checkError(rsc); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, rsc->getWidth(), rsc->getHeight()); + } +} + +void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) { + DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv; + if(drv->mFBOId != 0) { + glDeleteFramebuffers(1, &drv->mFBOId); + } + + free(fb->mHal.drv); + fb->mHal.drv = NULL; +} + + diff --git a/libs/rs/driver/rsdFrameBuffer.h b/libs/rs/driver/rsdFrameBuffer.h new file mode 100644 index 0000000..dec59fc --- /dev/null +++ b/libs/rs/driver/rsdFrameBuffer.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef RSD_FRAME_BUFFER_H +#define RSD_FRAME_BUFFER_H + +#include <rs_hal.h> + +bool rsdFrameBufferInit(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); +void rsdFrameBufferSetActive(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); +void rsdFrameBufferDestroy(const android::renderscript::Context *rsc, + const android::renderscript::FBOCache *fb); + + +#endif // RSD_FRAME_BUFFER_H diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp new file mode 100644 index 0000000..a70589b --- /dev/null +++ b/libs/rs/driver/rsdGL.cpp @@ -0,0 +1,369 @@ +/* + * 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 <ui/FramebufferNativeWindow.h> +#include <ui/PixelFormat.h> +#include <ui/EGLUtils.h> +#include <ui/egl/android_natives.h> + +#include <sys/types.h> +#include <sys/resource.h> +#include <sched.h> + +#include <cutils/properties.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <string.h> + +#include "rsdCore.h" +#include "rsdGL.h" + +#include <malloc.h> +#include "rsContext.h" +#include "rsdShaderCache.h" +#include "rsdVertexArray.h" + +using namespace android; +using namespace android::renderscript; + +static int32_t gGLContextCount = 0; + +static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + if (returnVal != EGL_TRUE) { + fprintf(stderr, "%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), + error); + } +} + +static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { + +#define X(VAL) {VAL, #VAL} + struct {EGLint attribute; const char* name;} names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + LOGV(" %s: %d (0x%x)", names[j].name, value, value); + } + } +} + +static void DumpDebug(RsdHal *dc) { + LOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion); + LOGE(" EGL context %p surface %p, Display=%p", dc->gl.egl.context, dc->gl.egl.surface, + dc->gl.egl.display); + LOGE(" GL vendor: %s", dc->gl.gl.vendor); + LOGE(" GL renderer: %s", dc->gl.gl.renderer); + LOGE(" GL Version: %s", dc->gl.gl.version); + LOGE(" GL Extensions: %s", dc->gl.gl.extensions); + LOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion); + + LOGV("MAX Textures %i, %i %i", dc->gl.gl.maxVertexTextureUnits, + dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits); + LOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs); + LOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors, + dc->gl.gl.maxFragmentUniformVectors); + LOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors); +} + +void rsdGLShutdown(const Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.shaderCache->cleanupAll(); + delete dc->gl.shaderCache; + + delete dc->gl.vertexArrayState; + + LOGV("%p, deinitEGL", rsc); + + if (dc->gl.egl.context != EGL_NO_CONTEXT) { + eglMakeCurrent(dc->gl.egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surfaceDefault); + if (dc->gl.egl.surface != EGL_NO_SURFACE) { + eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface); + } + eglDestroyContext(dc->gl.egl.display, dc->gl.egl.context); + checkEglError("eglDestroyContext"); + } + + gGLContextCount--; + if (!gGLContextCount) { + eglTerminate(dc->gl.egl.display); + } +} + +bool rsdGLInit(const Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + dc->gl.egl.numConfigs = -1; + EGLint configAttribs[128]; + EGLint *configAttribsPtr = configAttribs; + EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + + memset(configAttribs, 0, sizeof(configAttribs)); + + configAttribsPtr[0] = EGL_SURFACE_TYPE; + configAttribsPtr[1] = EGL_WINDOW_BIT; + configAttribsPtr += 2; + + configAttribsPtr[0] = EGL_RENDERABLE_TYPE; + configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; + configAttribsPtr += 2; + + if (rsc->mUserSurfaceConfig.depthMin > 0) { + configAttribsPtr[0] = EGL_DEPTH_SIZE; + configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin; + configAttribsPtr += 2; + } + + if (rsc->mDev->mForceSW) { + configAttribsPtr[0] = EGL_CONFIG_CAVEAT; + configAttribsPtr[1] = EGL_SLOW_CONFIG; + configAttribsPtr += 2; + } + + configAttribsPtr[0] = EGL_NONE; + rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); + + LOGV("%p initEGL start", rsc); + dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); + + eglInitialize(dc->gl.egl.display, &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion); + checkEglError("eglInitialize"); + + PixelFormat pf = PIXEL_FORMAT_RGBA_8888; + if (rsc->mUserSurfaceConfig.alphaMin == 0) { + pf = PIXEL_FORMAT_RGBX_8888; + } + + status_t err = EGLUtils::selectConfigForPixelFormat(dc->gl.egl.display, configAttribs, + pf, &dc->gl.egl.config); + if (err) { + LOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc); + } + //if (props.mLogVisual) { + if (0) { + printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config); + } + //} + + dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config, + EGL_NO_CONTEXT, context_attribs2); + checkEglError("eglCreateContext"); + if (dc->gl.egl.context == EGL_NO_CONTEXT) { + LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc); + return false; + } + gGLContextCount++; + + + EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config, + pbuffer_attribs); + checkEglError("eglCreatePbufferSurface"); + if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) { + LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE"); + rsdGLShutdown(rsc); + return false; + } + + EGLBoolean ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, + dc->gl.egl.surfaceDefault, dc->gl.egl.context); + if (ret == EGL_FALSE) { + LOGE("eglMakeCurrent returned EGL_FALSE"); + checkEglError("eglMakeCurrent", ret); + rsdGLShutdown(rsc); + return false; + } + + dc->gl.gl.version = glGetString(GL_VERSION); + dc->gl.gl.vendor = glGetString(GL_VENDOR); + dc->gl.gl.renderer = glGetString(GL_RENDERER); + dc->gl.gl.extensions = glGetString(GL_EXTENSIONS); + + //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); + //LOGV("GL Version %s", mGL.mVersion); + //LOGV("GL Vendor %s", mGL.mVendor); + //LOGV("GL Renderer %s", mGL.mRenderer); + //LOGV("GL Extensions %s", mGL.mExtensions); + + const char *verptr = NULL; + if (strlen((const char *)dc->gl.gl.version) > 9) { + if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) { + verptr = (const char *)dc->gl.gl.version + 12; + } + if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) { + verptr = (const char *)dc->gl.gl.version + 9; + } + } + + if (!verptr) { + LOGE("Error, OpenGL ES Lite not supported"); + rsdGLShutdown(rsc); + return false; + } else { + sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion); + } + + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits); + + glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits); + + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors); + + dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_OES_texture_npot"); + dc->gl.gl.GL_IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_IMG_texture_npot"); + dc->gl.gl.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_NV_texture_npot_2D_mipmap"); + dc->gl.gl.EXT_texture_max_aniso = 1.0f; + bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions, + "GL_EXT_texture_filter_anisotropic"); + if (hasAniso) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso); + } + + if (0) { + DumpDebug(dc); + } + + dc->gl.shaderCache = new RsdShaderCache(); + dc->gl.vertexArrayState = new RsdVertexArrayState(); + dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs); + + LOGV("initGLThread end %p", rsc); + return true; +} + + +bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + EGLBoolean ret; + // WAR: Some drivers fail to handle 0 size surfaces correcntly. + // Use the pbuffer to avoid this pitfall. + if ((dc->gl.egl.surface != NULL) || (w == 0) || (h == 0)) { + ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, + dc->gl.egl.surfaceDefault, dc->gl.egl.context); + checkEglError("eglMakeCurrent", ret); + + ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface); + checkEglError("eglDestroySurface", ret); + + dc->gl.egl.surface = NULL; + dc->gl.width = 1; + dc->gl.height = 1; + } + + dc->gl.wndSurface = (ANativeWindow *)sur; + if (dc->gl.wndSurface != NULL) { + dc->gl.width = w; + dc->gl.height = h; + + dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config, + dc->gl.wndSurface, NULL); + checkEglError("eglCreateWindowSurface"); + if (dc->gl.egl.surface == EGL_NO_SURFACE) { + LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); + } + + ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface, + dc->gl.egl.surface, dc->gl.egl.context); + checkEglError("eglMakeCurrent", ret); + } + return true; +} + +void rsdGLSwap(const android::renderscript::Context *rsc) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + eglSwapBuffers(dc->gl.egl.display, dc->gl.egl.surface); +} + +void rsdGLCheckError(const android::renderscript::Context *rsc, + const char *msg, bool isFatal) { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + char buf[1024]; + snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg); + + if (isFatal) { + rsc->setError(RS_ERROR_FATAL_DRIVER, buf); + } else { + switch (err) { + case GL_OUT_OF_MEMORY: + rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf); + break; + default: + rsc->setError(RS_ERROR_DRIVER, buf); + break; + } + } + + LOGE("%p, %s", rsc, buf); + } + +} diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h new file mode 100644 index 0000000..01c8438 --- /dev/null +++ b/libs/rs/driver/rsdGL.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef RSD_GL_H +#define RSD_GL_H + +#include <rs_hal.h> +#include <EGL/egl.h> + +class RsdShaderCache; +class RsdVertexArrayState; + +typedef void (* InvokeFunc_t)(void); +typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); + +typedef struct RsdGLRec { + struct { + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLSurface surfaceDefault; + EGLDisplay display; + } egl; + + struct { + const uint8_t * vendor; + const uint8_t * renderer; + const uint8_t * version; + const uint8_t * extensions; + + uint32_t majorVersion; + uint32_t minorVersion; + + int32_t maxVaryingVectors; + int32_t maxTextureImageUnits; + + int32_t maxFragmentTextureImageUnits; + int32_t maxFragmentUniformVectors; + + int32_t maxVertexAttribs; + int32_t maxVertexUniformVectors; + int32_t maxVertexTextureUnits; + + bool OES_texture_npot; + bool GL_IMG_texture_npot; + bool GL_NV_texture_npot_2D_mipmap; + float EXT_texture_max_aniso; + } gl; + + ANativeWindow *wndSurface; + uint32_t width; + uint32_t height; + RsdShaderCache *shaderCache; + RsdVertexArrayState *vertexArrayState; +} RsdGL; + + + +bool rsdGLInit(const android::renderscript::Context *rsc); +void rsdGLShutdown(const android::renderscript::Context *rsc); +bool rsdGLSetSurface(const android::renderscript::Context *rsc, + uint32_t w, uint32_t h, RsNativeWindow sur); +void rsdGLSwap(const android::renderscript::Context *rsc); +void rsdGLCheckError(const android::renderscript::Context *rsc, + const char *msg, bool isFatal = false); + +#endif + diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp new file mode 100644 index 0000000..eb62ddb --- /dev/null +++ b/libs/rs/driver/rsdMesh.cpp @@ -0,0 +1,60 @@ +/* + * 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 <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdCore.h" +#include "rsdMesh.h" +#include "rsdMeshObj.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +bool rsdMeshInit(const Context *rsc, const Mesh *m) { + RsdMeshObj *drv = NULL; + if(m->mHal.drv) { + drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } + drv = new RsdMeshObj(rsc, m); + m->mHal.drv = drv; + return drv->init(); +} + +void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { + if(m->mHal.drv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + drv->renderPrimitiveRange(rsc, primIndex, start, len); + } +} + +void rsdMeshDestroy(const Context *rsc, const Mesh *m) { + if(m->mHal.drv) { + RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv; + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h new file mode 100644 index 0000000..d2714fd --- /dev/null +++ b/libs/rs/driver/rsdMesh.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef RSD_MESH_H +#define RSD_MESH_H + +#include <rs_hal.h> + + +bool rsdMeshInit(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); +void rsdMeshDraw(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m, + uint32_t primIndex, uint32_t start, uint32_t len); +void rsdMeshDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Mesh *m); + + +#endif diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp new file mode 100644 index 0000000..c220ac1 --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.cpp @@ -0,0 +1,194 @@ +/* + * 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 <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsMesh.h> + +#include "rsdAllocation.h" +#include "rsdMeshObj.h" +#include "rsdGL.h" + +using namespace android; +using namespace android::renderscript; + +RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) { + mRSMesh = rsMesh; + + mAttribs = NULL; + mAttribAllocationIndex = NULL; + mGLPrimitives = NULL; + + mAttribCount = 0; +} + +RsdMeshObj::~RsdMeshObj() { + if (mAttribs) { + delete[] mAttribs; + delete[] mAttribAllocationIndex; + } + if (mGLPrimitives) { + delete[] mGLPrimitives; + } +} + +bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { + // Do not create attribs for padding + if (elem->getFieldName(fieldIdx)[0] == '#') { + return false; + } + + // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. + // Filter rs types accordingly + RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); + if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && + dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && + dt != RS_TYPE_SIGNED_16) { + return false; + } + + // Now make sure they are not arrays + uint32_t arraySize = elem->getFieldArraySize(fieldIdx); + if (arraySize != 1) { + return false; + } + + return true; +} + +bool RsdMeshObj::init() { + + updateGLPrimitives(); + + // Count the number of gl attrs to initialize + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { + if (isValidGLComponent(elem, ct)) { + mAttribCount ++; + } + } + } + + if (mAttribs) { + delete [] mAttribs; + delete [] mAttribAllocationIndex; + mAttribs = NULL; + mAttribAllocationIndex = NULL; + } + if (!mAttribCount) { + return false; + } + + mAttribs = new RsdVertexArray::Attrib[mAttribCount]; + mAttribAllocationIndex = new uint32_t[mAttribCount]; + + uint32_t userNum = 0; + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); + uint32_t stride = elem->getSizeBytes(); + for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { + const Component &c = elem->getField(fieldI)->getComponent(); + + if (!isValidGLComponent(elem, fieldI)) { + continue; + } + + mAttribs[userNum].size = c.getVectorSize(); + mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); + mAttribs[userNum].type = rsdTypeToGLType(c.getType()); + mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); + mAttribs[userNum].stride = stride; + String8 tmp(RS_SHADER_ATTR); + tmp.append(elem->getFieldName(fieldI)); + mAttribs[userNum].name.setTo(tmp.string()); + + // Remember which allocation this attribute came from + mAttribAllocationIndex[userNum] = ct; + userNum ++; + } + } + + return true; +} + +void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { + if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) { + LOGE("Invalid mesh or parameters"); + return; + } + + for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { + const Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[ct].get(); + rsdAllocationSyncAll(rsc, alloc, RS_ALLOCATION_USAGE_SCRIPT); + } + + // update attributes with either buffer information or data ptr based on their current state + for (uint32_t ct=0; ct < mAttribCount; ct++) { + uint32_t allocIndex = mAttribAllocationIndex[ct]; + Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get(); + DrvAllocation *drvAlloc = (DrvAllocation *)alloc->mHal.drv; + + if (drvAlloc->bufferID) { + mAttribs[ct].buffer = drvAlloc->bufferID; + mAttribs[ct].ptr = NULL; + } else { + mAttribs[ct].buffer = 0; + mAttribs[ct].ptr = (const uint8_t*)drvAlloc->mallocPtr; + } + } + + RsdVertexArray va(mAttribs, mAttribCount); + va.setup(rsc); + + Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex]; + const Allocation *idxAlloc = prim->mIndexBuffer.get(); + if (idxAlloc) { + DrvAllocation *drvAlloc = (DrvAllocation *)idxAlloc->mHal.drv; + rsdAllocationSyncAll(rsc, idxAlloc, RS_ALLOCATION_USAGE_SCRIPT); + + if (drvAlloc->bufferID) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID); + glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, drvAlloc->mallocPtr); + } + } else { + glDrawArrays(mGLPrimitives[primIndex], start, len); + } + + rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange"); +} + +void RsdMeshObj::updateGLPrimitives() { + mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount]; + for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) { + switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) { + case RS_PRIMITIVE_POINT: mGLPrimitives[i] = GL_POINTS; break; + case RS_PRIMITIVE_LINE: mGLPrimitives[i] = GL_LINES; break; + case RS_PRIMITIVE_LINE_STRIP: mGLPrimitives[i] = GL_LINE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break; + case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break; + case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break; + } + } +} diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h new file mode 100644 index 0000000..8b1271b --- /dev/null +++ b/libs/rs/driver/rsdMeshObj.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef ANDROID_RSD_MESH_OBJ_H +#define ANDROID_RSD_MESH_OBJ_H + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + + class Context; + class Mesh; + class Element; + +} +} + +#include "driver/rsdVertexArray.h" + +// An element is a group of Components that occupies one cell in a structure. +class RsdMeshObj { +public: + RsdMeshObj(const android::renderscript::Context *, + const android::renderscript::Mesh *); + ~RsdMeshObj(); + + void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; + + bool init(); + +protected: + const android::renderscript::Mesh *mRSMesh; + + uint32_t *mGLPrimitives; + void updateGLPrimitives(); + + bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx); + // Attribues that allow us to map to GL + RsdVertexArray::Attrib *mAttribs; + // This allows us to figure out which allocation the attribute + // belongs to. In the event the allocation is uploaded to GL + // buffer, it lets us properly map it + uint32_t *mAttribAllocationIndex; + uint32_t mAttribCount; +}; + +#endif //ANDROID_RSD_MESH_OBJ_H + + + diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp new file mode 100644 index 0000000..39b3805 --- /dev/null +++ b/libs/rs/driver/rsdProgram.cpp @@ -0,0 +1,108 @@ +/* + * 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 "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdProgramVertex.h" +#include "rsdShader.h" +#include "rsdShaderCache.h" + +#include "rsContext.h" +#include "rsProgramVertex.h" +#include "rsProgramFragment.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen); + pv->mHal.drv = drv; + + return drv->createShader(); +} + +static void SyncProgramConstants(const Context *rsc, const Program *p) { + for (uint32_t ct=0; ct < p->mHal.state.texturesCount; ct++) { + const Allocation *a = p->mHal.state.textures[ct].get(); + DrvAllocation *drvAlloc = (DrvAllocation *)a->mHal.drv; + if (drvAlloc->uploadDeferred) { + rsdAllocationSyncAll(rsc, a, RS_ALLOCATION_USAGE_SCRIPT); + } + } +} + +void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + SyncProgramConstants(rsc, pv); + dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv); +} + +void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pv->mHal.drv) { + drv = (RsdShader*)pv->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying vertex shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupVertex(drv->getShaderID()); + } + delete drv; + } +} + +bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf, + const char* shader, uint32_t shaderLen) { + RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen); + pf->mHal.drv = drv; + + return drv->createShader(); +} + +void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + SyncProgramConstants(rsc, pf); + dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv); +} + +void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + RsdShader *drv = NULL; + if(pf->mHal.drv) { + drv = (RsdShader*)pf->mHal.drv; + if (rsc->props.mLogShaders) { + LOGV("Destroying fragment shader with ID %u", drv->getShaderID()); + } + if (drv->getShaderID()) { + dc->gl.shaderCache->cleanupFragment(drv->getShaderID()); + } + delete drv; + } +} + + diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h new file mode 100644 index 0000000..366cb40 --- /dev/null +++ b/libs/rs/driver/rsdProgramFragment.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef RSD_PROGRAM_FRAGMENT_H +#define RSD_PROGRAM_FRAGMENT_H + +#include <rs_hal.h> + + +bool rsdProgramFragmentInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *, + const char* shader, uint32_t shaderLen); +void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); +void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramFragment *); + + +#endif //RSD_PROGRAM_Fragment_H diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp new file mode 100644 index 0000000..65995be --- /dev/null +++ b/libs/rs/driver/rsdProgramRaster.cpp @@ -0,0 +1,55 @@ +/* + * 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 "rsdCore.h" +#include "rsdProgramStore.h" + +#include "rsContext.h" +#include "rsProgramStore.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +bool rsdProgramRasterInit(const Context *, const ProgramRaster *) { + return true; +} + +void rsdProgramRasterSetActive(const Context *, const ProgramRaster *pr) { + switch (pr->mHal.state.cull) { + case RS_CULL_BACK: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case RS_CULL_FRONT: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + case RS_CULL_NONE: + glDisable(GL_CULL_FACE); + break; + } + +} + +void rsdProgramRasterDestroy(const Context *, const ProgramRaster *) { +} + + diff --git a/libs/rs/driver/rsdProgramRaster.h b/libs/rs/driver/rsdProgramRaster.h new file mode 100644 index 0000000..20adaad --- /dev/null +++ b/libs/rs/driver/rsdProgramRaster.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef RSD_PROGRAM_RASTER_H +#define RSD_PROGRAM_RASTER_H + +#include <rs_hal.h> + + +bool rsdProgramRasterInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); +void rsdProgramRasterSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); +void rsdProgramRasterDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramRaster *); + + +#endif diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp new file mode 100644 index 0000000..e591453 --- /dev/null +++ b/libs/rs/driver/rsdProgramStore.cpp @@ -0,0 +1,204 @@ +/* + * 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 "rsdCore.h" +#include "rsdProgramStore.h" + +#include "rsContext.h" +#include "rsProgramStore.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +struct DrvProgramStore { + GLenum blendSrc; + GLenum blendDst; + bool blendEnable; + + GLenum depthFunc; + bool depthTestEnable; +}; + +bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) { + DrvProgramStore *drv = (DrvProgramStore *)calloc(1, sizeof(DrvProgramStore)); + if (drv == NULL) { + return false; + } + + ps->mHal.drv = drv; + drv->depthTestEnable = true; + + switch (ps->mHal.state.depthFunc) { + case RS_DEPTH_FUNC_ALWAYS: + drv->depthTestEnable = false; + drv->depthFunc = GL_ALWAYS; + break; + case RS_DEPTH_FUNC_LESS: + drv->depthFunc = GL_LESS; + break; + case RS_DEPTH_FUNC_LEQUAL: + drv->depthFunc = GL_LEQUAL; + break; + case RS_DEPTH_FUNC_GREATER: + drv->depthFunc = GL_GREATER; + break; + case RS_DEPTH_FUNC_GEQUAL: + drv->depthFunc = GL_GEQUAL; + break; + case RS_DEPTH_FUNC_EQUAL: + drv->depthFunc = GL_EQUAL; + break; + case RS_DEPTH_FUNC_NOTEQUAL: + drv->depthFunc = GL_NOTEQUAL; + break; + default: + LOGE("Unknown depth function."); + goto error; + } + + + + drv->blendEnable = true; + if ((ps->mHal.state.blendSrc == RS_BLEND_SRC_ONE) && + (ps->mHal.state.blendDst == RS_BLEND_DST_ZERO)) { + drv->blendEnable = false; + } + + switch (ps->mHal.state.blendSrc) { + case RS_BLEND_SRC_ZERO: + drv->blendSrc = GL_ZERO; + break; + case RS_BLEND_SRC_ONE: + drv->blendSrc = GL_ONE; + break; + case RS_BLEND_SRC_DST_COLOR: + drv->blendSrc = GL_DST_COLOR; + break; + case RS_BLEND_SRC_ONE_MINUS_DST_COLOR: + drv->blendSrc = GL_ONE_MINUS_DST_COLOR; + break; + case RS_BLEND_SRC_SRC_ALPHA: + drv->blendSrc = GL_SRC_ALPHA; + break; + case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA: + drv->blendSrc = GL_ONE_MINUS_SRC_ALPHA; + break; + case RS_BLEND_SRC_DST_ALPHA: + drv->blendSrc = GL_DST_ALPHA; + break; + case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA: + drv->blendSrc = GL_ONE_MINUS_DST_ALPHA; + break; + case RS_BLEND_SRC_SRC_ALPHA_SATURATE: + drv->blendSrc = GL_SRC_ALPHA_SATURATE; + break; + default: + LOGE("Unknown blend src mode."); + goto error; + } + + switch (ps->mHal.state.blendDst) { + case RS_BLEND_DST_ZERO: + drv->blendDst = GL_ZERO; + break; + case RS_BLEND_DST_ONE: + drv->blendDst = GL_ONE; + break; + case RS_BLEND_DST_SRC_COLOR: + drv->blendDst = GL_SRC_COLOR; + break; + case RS_BLEND_DST_ONE_MINUS_SRC_COLOR: + drv->blendDst = GL_ONE_MINUS_SRC_COLOR; + break; + case RS_BLEND_DST_SRC_ALPHA: + drv->blendDst = GL_SRC_ALPHA; + break; + case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA: + drv->blendDst = GL_ONE_MINUS_SRC_ALPHA; + break; + case RS_BLEND_DST_DST_ALPHA: + drv->blendDst = GL_DST_ALPHA; + break; + case RS_BLEND_DST_ONE_MINUS_DST_ALPHA: + drv->blendDst = GL_ONE_MINUS_DST_ALPHA; + break; + default: + LOGE("Unknown blend dst mode."); + goto error; + } + + return true; + +error: + free(drv); + ps->mHal.drv = NULL; + return false; +} + +void rsdProgramStoreSetActive(const Context *rsc, const ProgramStore *ps) { + DrvProgramStore *drv = (DrvProgramStore *)ps->mHal.drv; + + glColorMask(ps->mHal.state.colorRWriteEnable, + ps->mHal.state.colorGWriteEnable, + ps->mHal.state.colorBWriteEnable, + ps->mHal.state.colorAWriteEnable); + + if (drv->blendEnable) { + glEnable(GL_BLEND); + glBlendFunc(drv->blendSrc, drv->blendDst); + } else { + glDisable(GL_BLEND); + } + + if (rsc->mUserSurfaceConfig.depthMin > 0) { + glDepthMask(ps->mHal.state.depthWriteEnable); + if (drv->depthTestEnable || ps->mHal.state.depthWriteEnable) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(drv->depthFunc); + } else { + glDisable(GL_DEPTH_TEST); + } + } else { + glDepthMask(false); + glDisable(GL_DEPTH_TEST); + } + + /* + if (rsc->mUserSurfaceConfig.stencilMin > 0) { + } else { + glStencilMask(0); + glDisable(GL_STENCIL_TEST); + } + */ + + if (ps->mHal.state.ditherEnable) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } +} + +void rsdProgramStoreDestroy(const Context *rsc, const ProgramStore *ps) { + free(ps->mHal.drv); + ps->mHal.drv = NULL; +} + + diff --git a/libs/rs/driver/rsdProgramStore.h b/libs/rs/driver/rsdProgramStore.h new file mode 100644 index 0000000..217a0ce --- /dev/null +++ b/libs/rs/driver/rsdProgramStore.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef RSD_PROGRAM_STORE_H +#define RSD_PROGRAM_STORE_H + +#include <rs_hal.h> + + +bool rsdProgramStoreInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); +void rsdProgramStoreSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); +void rsdProgramStoreDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramStore *ps); + + +#endif diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h new file mode 100644 index 0000000..e998572 --- /dev/null +++ b/libs/rs/driver/rsdProgramVertex.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef RSD_PROGRAM_VERTEX_H +#define RSD_PROGRAM_VERTEX_H + +#include <rs_hal.h> + +bool rsdProgramVertexInit(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *, + const char* shader, uint32_t shaderLen); +void rsdProgramVertexSetActive(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); +void rsdProgramVertexDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ProgramVertex *); + + +#endif //RSD_PROGRAM_VERTEX_H diff --git a/libs/rs/driver/rsdRuntime.h b/libs/rs/driver/rsdRuntime.h new file mode 100644 index 0000000..840eced --- /dev/null +++ b/libs/rs/driver/rsdRuntime.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef RSD_RUNTIME_STUBS_H +#define RSD_RUNTIME_STUBS_H + +#include <rs_hal.h> +#include <bcc/bcc.h> + +#include "rsMutex.h" + +const RsdSymbolTable * rsdLookupSymbolMath(const char *sym); + +void* rsdLookupRuntimeStub(void* pContext, char const* name); + +#endif diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/driver/rsdRuntimeMath.cpp index 8a0aa47..acb990d 100644 --- a/libs/rs/rsScriptC_LibCL.cpp +++ b/libs/rs/driver/rsdRuntimeMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -16,8 +16,12 @@ #include "rsContext.h" #include "rsScriptC.h" +#include "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" -// Implements rs_cl.rsh +#include "rsdCore.h" +#include "rsdRuntime.h" using namespace android; @@ -135,6 +139,135 @@ static float SC_sign_f32(float value) { return value; } +static void SC_MatrixLoadIdentity_4x4(Matrix4x4 *m) { + m->loadIdentity(); +} +static void SC_MatrixLoadIdentity_3x3(Matrix3x3 *m) { + m->loadIdentity(); +} +static void SC_MatrixLoadIdentity_2x2(Matrix2x2 *m) { + m->loadIdentity(); +} + +static void SC_MatrixLoad_4x4_f(Matrix4x4 *m, const float *f) { + m->load(f); +} +static void SC_MatrixLoad_3x3_f(Matrix3x3 *m, const float *f) { + m->load(f); +} +static void SC_MatrixLoad_2x2_f(Matrix2x2 *m, const float *f) { + m->load(f); +} + +static void SC_MatrixLoad_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *s) { + m->load(s); +} +static void SC_MatrixLoad_4x4_3x3(Matrix4x4 *m, const Matrix3x3 *s) { + m->load(s); +} +static void SC_MatrixLoad_4x4_2x2(Matrix4x4 *m, const Matrix2x2 *s) { + m->load(s); +} +static void SC_MatrixLoad_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *s) { + m->load(s); +} +static void SC_MatrixLoad_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *s) { + m->load(s); +} + +static void SC_MatrixLoadRotate(Matrix4x4 *m, float rot, float x, float y, float z) { + m->loadRotate(rot, x, y, z); +} +static void SC_MatrixLoadScale(Matrix4x4 *m, float x, float y, float z) { + m->loadScale(x, y, z); +} +static void SC_MatrixLoadTranslate(Matrix4x4 *m, float x, float y, float z) { + m->loadTranslate(x, y, z); +} +static void SC_MatrixRotate(Matrix4x4 *m, float rot, float x, float y, float z) { + m->rotate(rot, x, y, z); +} +static void SC_MatrixScale(Matrix4x4 *m, float x, float y, float z) { + m->scale(x, y, z); +} +static void SC_MatrixTranslate(Matrix4x4 *m, float x, float y, float z) { + m->translate(x, y, z); +} + +static void SC_MatrixLoadMultiply_4x4_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *lhs, const Matrix4x4 *rhs) { + m->loadMultiply(lhs, rhs); +} +static void SC_MatrixLoadMultiply_3x3_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *lhs, const Matrix3x3 *rhs) { + m->loadMultiply(lhs, rhs); +} +static void SC_MatrixLoadMultiply_2x2_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *lhs, const Matrix2x2 *rhs) { + m->loadMultiply(lhs, rhs); +} + +static void SC_MatrixMultiply_4x4_4x4(Matrix4x4 *m, const Matrix4x4 *rhs) { + m->multiply(rhs); +} +static void SC_MatrixMultiply_3x3_3x3(Matrix3x3 *m, const Matrix3x3 *rhs) { + m->multiply(rhs); +} +static void SC_MatrixMultiply_2x2_2x2(Matrix2x2 *m, const Matrix2x2 *rhs) { + m->multiply(rhs); +} + +static void SC_MatrixLoadOrtho(Matrix4x4 *m, float l, float r, float b, float t, float n, float f) { + m->loadOrtho(l, r, b, t, n, f); +} +static void SC_MatrixLoadFrustum(Matrix4x4 *m, float l, float r, float b, float t, float n, float f) { + m->loadFrustum(l, r, b, t, n, f); +} +static void SC_MatrixLoadPerspective(Matrix4x4 *m, float fovy, float aspect, float near, float far) { + m->loadPerspective(fovy, aspect, near, far); +} + +static bool SC_MatrixInverse_4x4(Matrix4x4 *m) { + return m->inverse(); +} +static bool SC_MatrixInverseTranspose_4x4(Matrix4x4 *m) { + return m->inverseTranspose(); +} +static void SC_MatrixTranspose_4x4(Matrix4x4 *m) { + m->transpose(); +} +static void SC_MatrixTranspose_3x3(Matrix3x3 *m) { + m->transpose(); +} +static void SC_MatrixTranspose_2x2(Matrix2x2 *m) { + m->transpose(); +} + +static float SC_randf(float max) { + float r = (float)rand(); + r *= max; + r /= RAND_MAX; + return r; +} + +static float SC_randf2(float min, float max) { + float r = (float)rand(); + r /= RAND_MAX; + r = r * (max - min) + min; + return r; +} + +static int SC_randi(int max) { + return (int)SC_randf(max); +} + +static int SC_randi2(int min, int max) { + return (int)SC_randf2(min, max); +} + +static float SC_frac(float v) { + int i = (int)floor(v); + return fmin(v - i, 0x1.fffffep-1f); +} + + ////////////////////////////////////////////////////////////////////////////// // Class implementation ////////////////////////////////////////////////////////////////////////////// @@ -156,8 +289,7 @@ static float SC_sign_f32(float value) { // ::= f # float // ::= d # double -static ScriptCState::SymbolTable_t gSyms[] = { - // OpenCL math +static RsdSymbolTable gSyms[] = { { "_Z4acosf", (void *)&acosf, true }, { "_Z5acoshf", (void *)&acoshf, true }, { "_Z4asinf", (void *)&asinf, true }, @@ -215,7 +347,6 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z6tgammaf", (void *)&tgammaf, true }, { "_Z5truncf", (void *)&truncf, true }, - // OpenCL Int { "_Z3absi", (void *)&SC_abs_i32, true }, { "_Z3abss", (void *)&SC_abs_i16, true }, { "_Z3absc", (void *)&SC_abs_i8, true }, @@ -238,7 +369,6 @@ static ScriptCState::SymbolTable_t gSyms[] = { { "_Z3minss", (void *)&SC_min_i16, true }, { "_Z3mincc", (void *)&SC_min_i8, true }, - // OpenCL 6.11.4 { "_Z5clampfff", (void *)&SC_clamp_f32, true }, { "_Z7degreesf", (void *)&SC_degrees, true }, { "_Z3maxff", (void *)&SC_max_f32, true }, @@ -249,11 +379,57 @@ static ScriptCState::SymbolTable_t gSyms[] = { //{ "smoothstep", (void *)&, true }, { "_Z4signf", (void *)&SC_sign_f32, true }, + // matrix + { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, true }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, true }, + { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, true }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, true }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, true }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, true }, + + { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, true }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, true }, + { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, true }, + { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, true }, + { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, true }, + + { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, true }, + { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, true }, + { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, true }, + { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, true }, + { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, true }, + { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, true }, + + { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, true }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, true }, + { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, true }, + { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, true }, + + { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, true }, + { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, true }, + { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, true }, + + { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, true }, + { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, true }, + { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true }, + + // RS Math + { "_Z6rsRandi", (void *)&SC_randi, true }, + { "_Z6rsRandii", (void *)&SC_randi2, true }, + { "_Z6rsRandf", (void *)&SC_randf, true }, + { "_Z6rsRandff", (void *)&SC_randf2, true }, + { "_Z6rsFracf", (void *)&SC_frac, true }, + { NULL, NULL, false } }; -const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(const char *sym) { - ScriptCState::SymbolTable_t *syms = gSyms; +const RsdSymbolTable * rsdLookupSymbolMath(const char *sym) { + const RsdSymbolTable *syms = gSyms; while (syms->mPtr) { if (!strcmp(syms->mName, sym)) { diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp new file mode 100644 index 0000000..9cbff95 --- /dev/null +++ b/libs/rs/driver/rsdRuntimeStubs.cpp @@ -0,0 +1,692 @@ +/* + * 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 "rsContext.h" +#include "rsScriptC.h" +#include "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" +#include "rsRuntime.h" + +#include "utils/Timers.h" +#include "rsdCore.h" + +#include "rsdRuntime.h" + +#include <time.h> + +using namespace android; +using namespace android::renderscript; + +#define GET_TLS() ScriptTLSStruct * tls = \ + (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey); \ + Context * rsc = tls->mContext; \ + ScriptC * sc = (ScriptC *) tls->mScript + + + +////////////////////////////////////////////////////////////////////////////// +// Allocation +////////////////////////////////////////////////////////////////////////////// + +static uint32_t SC_allocGetDimX(Allocation *a) { + return a->mHal.state.dimensionX; +} + +static uint32_t SC_allocGetDimY(Allocation *a) { + return a->mHal.state.dimensionY; +} + +static uint32_t SC_allocGetDimZ(Allocation *a) { + return a->mHal.state.dimensionZ; +} + +static uint32_t SC_allocGetDimLOD(Allocation *a) { + return a->mHal.state.hasMipmaps; +} + +static uint32_t SC_allocGetDimFaces(Allocation *a) { + return a->mHal.state.hasFaces; +} + +static const void * SC_getElementAtX(Allocation *a, uint32_t x) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * x]; +} + +static const void * SC_getElementAtXY(Allocation *a, uint32_t x, uint32_t y) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX)]; +} + +static const void * SC_getElementAtXYZ(Allocation *a, uint32_t x, uint32_t y, uint32_t z) { + const uint8_t *p = (const uint8_t *)a->getPtr(); + return &p[a->mHal.state.elementSizeBytes * (x + y * a->mHal.state.dimensionX + + z * a->mHal.state.dimensionX * a->mHal.state.dimensionY)]; +} + +static void SC_AllocationSyncAll2(Allocation *a, RsAllocationUsageType source) { + GET_TLS(); + rsrAllocationSyncAll(rsc, sc, a, source); +} + +static void SC_AllocationSyncAll(Allocation *a) { + GET_TLS(); + rsrAllocationSyncAll(rsc, sc, a, RS_ALLOCATION_USAGE_SCRIPT); +} + +const Allocation * SC_getAllocation(const void *ptr) { + GET_TLS(); + return rsrGetAllocation(rsc, sc, ptr); +} + + +////////////////////////////////////////////////////////////////////////////// +// Context +////////////////////////////////////////////////////////////////////////////// + +static void SC_BindTexture(ProgramFragment *pf, uint32_t slot, Allocation *a) { + GET_TLS(); + rsrBindTexture(rsc, sc, pf, slot, a); +} + +static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) { + GET_TLS(); + rsrBindSampler(rsc, sc, pf, slot, s); +} + +static void SC_BindProgramStore(ProgramStore *ps) { + GET_TLS(); + rsrBindProgramStore(rsc, sc, ps); +} + +static void SC_BindProgramFragment(ProgramFragment *pf) { + GET_TLS(); + rsrBindProgramFragment(rsc, sc, pf); +} + +static void SC_BindProgramVertex(ProgramVertex *pv) { + GET_TLS(); + rsrBindProgramVertex(rsc, sc, pv); +} + +static void SC_BindProgramRaster(ProgramRaster *pr) { + GET_TLS(); + rsrBindProgramRaster(rsc, sc, pr); +} + +static void SC_BindFrameBufferObjectColorTarget(Allocation *a, uint32_t slot) { + GET_TLS(); + rsrBindFrameBufferObjectColorTarget(rsc, sc, a, slot); +} + +static void SC_BindFrameBufferObjectDepthTarget(Allocation *a) { + GET_TLS(); + rsrBindFrameBufferObjectDepthTarget(rsc, sc, a); +} + +static void SC_ClearFrameBufferObjectColorTarget(uint32_t slot) { + GET_TLS(); + rsrClearFrameBufferObjectColorTarget(rsc, sc, slot); +} + +static void SC_ClearFrameBufferObjectDepthTarget(Context *, Script *) { + GET_TLS(); + rsrClearFrameBufferObjectDepthTarget(rsc, sc); +} + +static void SC_ClearFrameBufferObjectTargets(Context *, Script *) { + GET_TLS(); + rsrClearFrameBufferObjectTargets(rsc, sc); +} + + +////////////////////////////////////////////////////////////////////////////// +// VP +////////////////////////////////////////////////////////////////////////////// + +static void SC_VpLoadProjectionMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadProjectionMatrix(rsc, sc, m); +} + +static void SC_VpLoadModelMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadModelMatrix(rsc, sc, m); +} + +static void SC_VpLoadTextureMatrix(const rsc_Matrix *m) { + GET_TLS(); + rsrVpLoadTextureMatrix(rsc, sc, m); +} + +static void SC_PfConstantColor(ProgramFragment *pf, float r, float g, float b, float a) { + GET_TLS(); + rsrPfConstantColor(rsc, sc, pf, r, g, b, a); +} + +static void SC_VpGetProjectionMatrix(rsc_Matrix *m) { + GET_TLS(); + rsrVpGetProjectionMatrix(rsc, sc, m); +} + + +////////////////////////////////////////////////////////////////////////////// +// Drawing +////////////////////////////////////////////////////////////////////////////// + +static void SC_DrawQuadTexCoords(float x1, float y1, float z1, float u1, float v1, + float x2, float y2, float z2, float u2, float v2, + float x3, float y3, float z3, float u3, float v3, + float x4, float y4, float z4, float u4, float v4) { + GET_TLS(); + rsrDrawQuadTexCoords(rsc, sc, + x1, y1, z1, u1, v1, + x2, y2, z2, u2, v2, + x3, y3, z3, u3, v3, + x4, y4, z4, u4, v4); +} + +static void SC_DrawQuad(float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4) { + GET_TLS(); + rsrDrawQuad(rsc, sc, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4); +} + +static void SC_DrawSpriteScreenspace(float x, float y, float z, float w, float h) { + GET_TLS(); + rsrDrawSpriteScreenspace(rsc, sc, x, y, z, w, h); +} + +static void SC_DrawRect(float x1, float y1, float x2, float y2, float z) { + GET_TLS(); + rsrDrawRect(rsc, sc, x1, y1, x2, y2, z); +} + +static void SC_DrawMesh(Mesh *m) { + GET_TLS(); + rsrDrawMesh(rsc, sc, m); +} + +static void SC_DrawMeshPrimitive(Mesh *m, uint32_t primIndex) { + GET_TLS(); + rsrDrawMeshPrimitive(rsc, sc, m, primIndex); +} + +static void SC_DrawMeshPrimitiveRange(Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { + GET_TLS(); + rsrDrawMeshPrimitiveRange(rsc, sc, m, primIndex, start, len); +} + +static void SC_MeshComputeBoundingBox(Mesh *m, + float *minX, float *minY, float *minZ, + float *maxX, float *maxY, float *maxZ) { + GET_TLS(); + rsrMeshComputeBoundingBox(rsc, sc, m, minX, minY, minZ, maxX, maxY, maxZ); +} + + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + + +static void SC_Color(float r, float g, float b, float a) { + GET_TLS(); + rsrColor(rsc, sc, r, g, b, a); +} + +static void SC_Finish() { + GET_TLS(); + rsrFinish(rsc, sc); +} + +static void SC_ClearColor(float r, float g, float b, float a) { + GET_TLS(); + rsrClearColor(rsc, sc, r, g, b, a); +} + +static void SC_ClearDepth(float v) { + GET_TLS(); + rsrClearDepth(rsc, sc, v); +} + +static uint32_t SC_GetWidth() { + GET_TLS(); + return rsrGetWidth(rsc, sc); +} + +static uint32_t SC_GetHeight() { + GET_TLS(); + return rsrGetHeight(rsc, sc); +} + +static void SC_DrawTextAlloc(Allocation *a, int x, int y) { + GET_TLS(); + rsrDrawTextAlloc(rsc, sc, a, x, y); +} + +static void SC_DrawText(const char *text, int x, int y) { + GET_TLS(); + rsrDrawText(rsc, sc, text, x, y); +} + +static void SC_MeasureTextAlloc(Allocation *a, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { + GET_TLS(); + rsrMeasureTextAlloc(rsc, sc, a, left, right, top, bottom); +} + +static void SC_MeasureText(const char *text, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { + GET_TLS(); + rsrMeasureText(rsc, sc, text, left, right, top, bottom); +} + +static void SC_BindFont(Font *f) { + GET_TLS(); + rsrBindFont(rsc, sc, f); +} + +static void SC_FontColor(float r, float g, float b, float a) { + GET_TLS(); + rsrFontColor(rsc, sc, r, g, b, a); +} + + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + +static void SC_SetObject(ObjectBase **dst, ObjectBase * src) { + GET_TLS(); + rsrSetObject(rsc, sc, dst, src); +} + +static void SC_ClearObject(ObjectBase **dst) { + GET_TLS(); + rsrClearObject(rsc, sc, dst); +} + +static bool SC_IsObject(const ObjectBase *src) { + GET_TLS(); + return rsrIsObject(rsc, sc, src); +} + + + + +static const Allocation * SC_GetAllocation(const void *ptr) { + GET_TLS(); + return rsrGetAllocation(rsc, sc, ptr); +} + +static void SC_ForEach(Script *target, + Allocation *in, + Allocation *out, + const void *usr, + const RsScriptCall *call) { + GET_TLS(); + rsrForEach(rsc, sc, target, in, out, usr, 0, NULL); +} + +static void SC_ForEach2(Script *target, + Allocation *in, + Allocation *out, + const void *usr, + const RsScriptCall *call) { + GET_TLS(); + rsrForEach(rsc, sc, target, in, out, usr, 0, call); +} + + + +////////////////////////////////////////////////////////////////////////////// +// Time routines +////////////////////////////////////////////////////////////////////////////// + +static float SC_GetDt() { + GET_TLS(); + return rsrGetDt(rsc, sc); +} + +time_t SC_Time(time_t *timer) { + GET_TLS(); + return rsrTime(rsc, sc, timer); +} + +tm* SC_LocalTime(tm *local, time_t *timer) { + GET_TLS(); + return rsrLocalTime(rsc, sc, local, timer); +} + +int64_t SC_UptimeMillis() { + GET_TLS(); + return rsrUptimeMillis(rsc, sc); +} + +int64_t SC_UptimeNanos() { + GET_TLS(); + return rsrUptimeNanos(rsc, sc); +} + +////////////////////////////////////////////////////////////////////////////// +// Message routines +////////////////////////////////////////////////////////////////////////////// + +static uint32_t SC_ToClient2(int cmdID, void *data, int len) { + GET_TLS(); + return rsrToClient(rsc, sc, cmdID, data, len); +} + +static uint32_t SC_ToClient(int cmdID) { + GET_TLS(); + return rsrToClient(rsc, sc, cmdID, NULL, 0); +} + +static uint32_t SC_ToClientBlocking2(int cmdID, void *data, int len) { + GET_TLS(); + return rsrToClientBlocking(rsc, sc, cmdID, data, len); +} + +static uint32_t SC_ToClientBlocking(int cmdID) { + GET_TLS(); + return rsrToClientBlocking(rsc, sc, cmdID, NULL, 0); +} + +int SC_divsi3(int a, int b) { + return a / b; +} + +int SC_modsi3(int a, int b) { + return a % b; +} + +unsigned int SC_udivsi3(unsigned int a, unsigned int b) { + return a / b; +} + +unsigned int SC_umodsi3(unsigned int a, unsigned int b) { + return a % b; +} + +static void SC_debugF(const char *s, float f) { + LOGD("%s %f, 0x%08x", s, f, *((int *) (&f))); +} +static void SC_debugFv2(const char *s, float f1, float f2) { + LOGD("%s {%f, %f}", s, f1, f2); +} +static void SC_debugFv3(const char *s, float f1, float f2, float f3) { + LOGD("%s {%f, %f, %f}", s, f1, f2, f3); +} +static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) { + LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); +} +static void SC_debugD(const char *s, double d) { + LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d))); +} +static void SC_debugFM4v4(const char *s, const float *f) { + LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); + LOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); + LOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); + LOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); +} +static void SC_debugFM3v3(const char *s, const float *f) { + LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]); + LOGD("%s %f, %f, %f", s, f[1], f[4], f[7]); + LOGD("%s %f, %f, %f}",s, f[2], f[5], f[8]); +} +static void SC_debugFM2v2(const char *s, const float *f) { + LOGD("%s {%f, %f", s, f[0], f[2]); + LOGD("%s %f, %f}",s, f[1], f[3]); +} + +static void SC_debugI32(const char *s, int32_t i) { + LOGD("%s %i 0x%x", s, i, i); +} +static void SC_debugU32(const char *s, uint32_t i) { + LOGD("%s %u 0x%x", s, i, i); +} +static void SC_debugLL64(const char *s, long long ll) { + LOGD("%s %lld 0x%llx", s, ll, ll); +} +static void SC_debugULL64(const char *s, unsigned long long ll) { + LOGD("%s %llu 0x%llx", s, ll, ll); +} + +static void SC_debugP(const char *s, const void *p) { + LOGD("%s %p", s, p); +} + + +////////////////////////////////////////////////////////////////////////////// +// Stub implementation +////////////////////////////////////////////////////////////////////////////// + +// llvm name mangling ref +// <builtin-type> ::= v # void +// ::= b # bool +// ::= c # char +// ::= a # signed char +// ::= h # unsigned char +// ::= s # short +// ::= t # unsigned short +// ::= i # int +// ::= j # unsigned int +// ::= l # long +// ::= m # unsigned long +// ::= x # long long, __int64 +// ::= y # unsigned long long, __int64 +// ::= f # float +// ::= d # double + +static RsdSymbolTable gSyms[] = { + { "__divsi3", (void *)&SC_divsi3, true }, + { "__modsi3", (void *)&SC_modsi3, true }, + { "__udivsi3", (void *)&SC_udivsi3, true }, + { "__umodsi3", (void *)&SC_umodsi3, true }, + { "memset", (void *)&memset, true }, + { "memcpy", (void *)&memcpy, true }, + + // Refcounting + { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP10rs_element", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject10rs_element", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_type", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_type", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject13rs_allocation", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject10rs_sampler", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject17rs_program_raster", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject16rs_program_store", (void *)&SC_IsObject, true }, + + { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_font", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_font", (void *)&SC_IsObject, true }, + + // Allocation ops + { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true }, + { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true }, + { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true }, + { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true }, + { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true }, + + { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true }, + { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true }, + { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true }, + + { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true }, + + { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_AllocationSyncAll, true }, + { "_Z20rsgAllocationSyncAll13rs_allocation", (void *)&SC_AllocationSyncAll, false }, + { "_Z20rsgAllocationSyncAll13rs_allocationj", (void *)&SC_AllocationSyncAll2, false }, + { "_Z15rsGetAllocationPKv", (void *)&SC_GetAllocation, true }, + + + // Messaging + + { "_Z14rsSendToClienti", (void *)&SC_ToClient, false }, + { "_Z14rsSendToClientiPKvj", (void *)&SC_ToClient2, false }, + { "_Z22rsSendToClientBlockingi", (void *)&SC_ToClientBlocking, false }, + { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_ToClientBlocking2, false }, + + { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_BindProgramFragment, false }, + { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_BindProgramStore, false }, + { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_BindProgramVertex, false }, + { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false }, + { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false }, + { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false }, + + { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false }, + { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false }, + { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadTextureMatrix, false }, + + { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_VpGetProjectionMatrix, false }, + + { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_PfConstantColor, false }, + + { "_Z11rsgGetWidthv", (void *)&SC_GetWidth, false }, + { "_Z12rsgGetHeightv", (void *)&SC_GetHeight, false }, + + + { "_Z11rsgDrawRectfffff", (void *)&SC_DrawRect, false }, + { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_DrawQuad, false }, + { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_DrawQuadTexCoords, false }, + { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_DrawSpriteScreenspace, false }, + + { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_DrawMesh, false }, + { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_DrawMeshPrimitive, false }, + { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false }, + { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false }, + + { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false }, + { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false }, + + { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false }, + { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false }, + { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false }, + { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false }, + + { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false }, + { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false }, + + { "_Z18rsgBindColorTarget13rs_allocationj", (void *)&SC_BindFrameBufferObjectColorTarget, false }, + { "_Z18rsgBindDepthTarget13rs_allocation", (void *)&SC_BindFrameBufferObjectDepthTarget, false }, + { "_Z19rsgClearColorTargetj", (void *)&SC_ClearFrameBufferObjectColorTarget, false }, + { "_Z19rsgClearDepthTargetv", (void *)&SC_ClearFrameBufferObjectDepthTarget, false }, + { "_Z24rsgClearAllRenderTargetsv", (void *)&SC_ClearFrameBufferObjectTargets, false }, + + { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false }, + { "_Z9rsForEach9rs_script13rs_allocationS0_PKvj", (void *)&SC_ForEach2, false }, + + // time + { "_Z6rsTimePi", (void *)&SC_Time, true }, + { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_LocalTime, true }, + { "_Z14rsUptimeMillisv", (void*)&SC_UptimeMillis, true }, + { "_Z13rsUptimeNanosv", (void*)&SC_UptimeNanos, true }, + { "_Z7rsGetDtv", (void*)&SC_GetDt, false }, + + // misc + { "_Z5colorffff", (void *)&SC_Color, false }, + { "_Z9rsgFinishv", (void *)&SC_Finish, false }, + + // Debug + { "_Z7rsDebugPKcf", (void *)&SC_debugF, true }, + { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true }, + { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true }, + { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true }, + { "_Z7rsDebugPKcd", (void *)&SC_debugD, true }, + { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true }, + { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true }, + { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true }, + { "_Z7rsDebugPKci", (void *)&SC_debugI32, true }, + { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true }, + // Both "long" and "unsigned long" need to be redirected to their + // 64-bit counterparts, since we have hacked Slang to use 64-bit + // for "long" on Arm (to be similar to Java). + { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true }, + { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true }, + { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true }, + { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true }, + { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true }, + + { NULL, NULL, false } +}; + + +void* rsdLookupRuntimeStub(void* pContext, char const* name) { + ScriptC *s = (ScriptC *)pContext; + if (!strcmp(name, "__isThreadable")) { + return (void*) s->mHal.info.isThreadable; + } else if (!strcmp(name, "__clearThreadable")) { + s->mHal.info.isThreadable = false; + return NULL; + } + + RsdSymbolTable *syms = gSyms; + const RsdSymbolTable *sym = rsdLookupSymbolMath(name); + + if (!sym) { + while (syms->mPtr) { + if (!strcmp(syms->mName, name)) { + sym = syms; + } + syms++; + } + } + + if (sym) { + s->mHal.info.isThreadable &= sym->threadable; + return sym->mPtr; + } + LOGE("ScriptC sym lookup failed for %s", name); + return NULL; +} + + diff --git a/libs/rs/driver/rsdSampler.cpp b/libs/rs/driver/rsdSampler.cpp new file mode 100644 index 0000000..af48c61 --- /dev/null +++ b/libs/rs/driver/rsdSampler.cpp @@ -0,0 +1,40 @@ +/* + * 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 "rsdCore.h" +#include "rsdSampler.h" + +#include "rsContext.h" +#include "rsSampler.h" +#include "rsProgramVertex.h" +#include "rsProgramFragment.h" + +#include <GLES/gl.h> +#include <GLES/glext.h> + + +using namespace android; +using namespace android::renderscript; + +bool rsdSamplerInit(const android::renderscript::Context *, + const android::renderscript::Sampler *) { + return true; +} + +void rsdSamplerDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *s) { +} diff --git a/libs/rs/driver/rsdSampler.h b/libs/rs/driver/rsdSampler.h new file mode 100644 index 0000000..3a64e9e --- /dev/null +++ b/libs/rs/driver/rsdSampler.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef RSD_SAMPLER_H +#define RSD_SAMPLER_H + +#include <rs_hal.h> + + +bool rsdSamplerInit(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + +void rsdSamplerDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + + +#endif // RSD_SAMPLER_H diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp new file mode 100644 index 0000000..15cc417 --- /dev/null +++ b/libs/rs/driver/rsdShader.cpp @@ -0,0 +1,537 @@ +/* + * 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 <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsProgram.h> + +#include "rsdCore.h" +#include "rsdAllocation.h" +#include "rsdShader.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +RsdShader::RsdShader(const Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength) { + + mUserShader.setTo(shaderText, shaderLength); + mRSProgram = p; + mType = type; + initMemberVars(); + initAttribAndUniformArray(); + init(); +} + +RsdShader::~RsdShader() { + if (mShaderID) { + glDeleteShader(mShaderID); + } + + delete[] mAttribNames; + delete[] mUniformNames; + delete[] mUniformArraySizes; +} + +void RsdShader::initMemberVars() { + mDirty = true; + mShaderID = 0; + mAttribCount = 0; + mUniformCount = 0; + + mAttribNames = NULL; + mUniformNames = NULL; + mUniformArraySizes = NULL; + + mIsValid = false; +} + +void RsdShader::init() { + uint32_t attribCount = 0; + uint32_t uniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); + } + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); + } + + mTextureUniformIndexStart = uniformCount; + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); + mUniformNames[uniformCount].setTo(buf); + mUniformArraySizes[uniformCount] = 1; + uniformCount++; + } +} + +String8 RsdShader::getGLSLInputString() const { + String8 s; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: s.append("attribute float ATTRIB_"); break; + case 2: s.append("attribute vec2 ATTRIB_"); break; + case 3: s.append("attribute vec3 ATTRIB_"); break; + case 4: s.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + s.append(e->getFieldName(field)); + s.append(";\n"); + } + } + return s; +} + +void RsdShader::appendAttributes() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *e = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("attribute float ATTRIB_"); break; + case 2: mShader.append("attribute vec2 ATTRIB_"); break; + case 3: mShader.append("attribute vec3 ATTRIB_"); break; + case 4: mShader.append("attribute vec4 ATTRIB_"); break; + default: + rsAssert(0); + } + + mShader.append(fn); + mShader.append(";\n"); + } + } +} + +void RsdShader::appendTextures() { + char buf[256]; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { + if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) { + snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); + } else { + snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); + } + mShader.append(buf); + } +} + +bool RsdShader::createShader() { + + if (mType == GL_FRAGMENT_SHADER) { + mShader.append("precision mediump float;\n"); + } + appendUserConstants(); + appendAttributes(); + appendTextures(); + + mShader.append(mUserShader); + + return true; +} + +bool RsdShader::loadShader(const Context *rsc) { + mShaderID = glCreateShader(mType); + rsAssert(mShaderID); + + if (rsc->props.mLogShaders) { + LOGV("Loading shader type %x, ID %i", mType, mShaderID); + LOGV("%s", mShader.string()); + } + + if (mShaderID) { + const char * ss = mShader.string(); + glShaderSource(mShaderID, 1, &ss, NULL); + glCompileShader(mShaderID); + + GLint compiled = 0; + glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); + LOGE("Could not compile shader \n%s\n", buf); + free(buf); + } + glDeleteShader(mShaderID); + mShaderID = 0; + rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); + return false; + } + } + } + + if (rsc->props.mLogShaders) { + LOGV("--Shader load result %x ", glGetError()); + } + mIsValid = true; + return true; +} + +void RsdShader::appendUserConstants() { + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fn = e->getFieldName(field); + + if (fn[0] == '#') { + continue; + } + + // Cannot be complex + rsAssert(!f->getFieldCount()); + if (f->getType() == RS_TYPE_MATRIX_4X4) { + mShader.append("uniform mat4 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_3X3) { + mShader.append("uniform mat3 UNI_"); + } else if (f->getType() == RS_TYPE_MATRIX_2X2) { + mShader.append("uniform mat2 UNI_"); + } else { + switch (f->getComponent().getVectorSize()) { + case 1: mShader.append("uniform float UNI_"); break; + case 2: mShader.append("uniform vec2 UNI_"); break; + case 3: mShader.append("uniform vec3 UNI_"); break; + case 4: mShader.append("uniform vec4 UNI_"); break; + default: + rsAssert(0); + } + } + + mShader.append(fn); + if (e->getFieldArraySize(field) > 1) { + mShader.appendFormat("[%d]", e->getFieldArraySize(field)); + } + mShader.append(";\n"); + } + } +} + +void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + uint32_t elementSize = field->getSizeBytes() / sizeof(float); + for (uint32_t i = 0; i < arraySize; i ++) { + if (arraySize > 1) { + LOGV("Array Element [%u]", i); + } + if (dataType == RS_TYPE_MATRIX_4X4) { + LOGV("Matrix4x4"); + LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); + LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); + LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); + LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + LOGV("Matrix3x3"); + LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); + LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); + LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + LOGV("Matrix2x2"); + LOGV("{%f, %f", fd[0], fd[2]); + LOGV(" %f, %f}", fd[1], fd[3]); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + LOGV("Uniform 1 = %f", fd[0]); + break; + case 2: + LOGV("Uniform 2 = %f %f", fd[0], fd[1]); + break; + case 3: + LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); + break; + case 4: + LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); + break; + default: + rsAssert(0); + } + } + LOGE("Element size %u data=%p", elementSize, fd); + fd += elementSize; + LOGE("New data=%p", fd); + } +} + +void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd, + int32_t slot, uint32_t arraySize ) { + RsDataType dataType = field->getType(); + if (dataType == RS_TYPE_MATRIX_4X4) { + glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_3X3) { + glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); + } else if (dataType == RS_TYPE_MATRIX_2X2) { + glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); + } else { + switch (field->getComponent().getVectorSize()) { + case 1: + glUniform1fv(slot, arraySize, fd); + break; + case 2: + glUniform2fv(slot, arraySize, fd); + break; + case 3: + glUniform3fv(slot, arraySize, fd); + break; + case 4: + glUniform4fv(slot, arraySize, fd); + break; + default: + rsAssert(0); + } + } +} + +void RsdShader::setupSampler(const Context *rsc, const Sampler *s, const Allocation *tex) { + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + GLenum trans[] = { + GL_NEAREST, //RS_SAMPLER_NEAREST, + GL_LINEAR, //RS_SAMPLER_LINEAR, + GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, + GL_REPEAT, //RS_SAMPLER_WRAP, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP + GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST + }; + + GLenum transNP[] = { + GL_NEAREST, //RS_SAMPLER_NEAREST, + GL_LINEAR, //RS_SAMPLER_LINEAR, + GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP, + GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP + GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST, + }; + + // This tells us the correct texture type + DrvAllocation *drvTex = (DrvAllocation *)tex->mHal.drv; + const GLenum target = drvTex->glTarget; + + if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) { + if (tex->getHasGraphicsMipmaps() && + (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) { + if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + } else { + switch (trans[s->mHal.state.minFilter]) { + case GL_LINEAR_MIPMAP_LINEAR: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + break; + default: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + break; + } + } + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]); + } + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]); + } else { + if (tex->getHasGraphicsMipmaps()) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]); + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]); + } + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]); + glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]); + glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]); + } + + float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso); + if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) { + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); + } + + rsdGLCheckError(rsc, "Sampler::setup tex env"); +} + +void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) { + if (mRSProgram->mHal.state.texturesCount == 0) { + return; + } + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + + uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount; + uint32_t numTexturesAvailable = dc->gl.gl.maxFragmentTextureImageUnits; + if (numTexturesToBind >= numTexturesAvailable) { + LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", + mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); + numTexturesToBind = numTexturesAvailable; + } + + for (uint32_t ct=0; ct < numTexturesToBind; ct++) { + glActiveTexture(GL_TEXTURE0 + ct); + if (!mRSProgram->mHal.state.textures[ct].get()) { + LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); + continue; + } + + DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv; + if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) { + LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); + } + glBindTexture(drvTex->glTarget, drvTex->textureID); + rsdGLCheckError(rsc, "ProgramFragment::setup tex bind"); + if (mRSProgram->mHal.state.samplers[ct].get()) { + setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get()); + } else { + glTexParameteri(drvTex->glTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(drvTex->glTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + rsdGLCheckError(rsc, "ProgramFragment::setup tex env"); + } + + glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); + rsdGLCheckError(rsc, "ProgramFragment::setup uniforms"); + } + + glActiveTexture(GL_TEXTURE0); + mDirty = false; + rsdGLCheckError(rsc, "ProgramFragment::setup"); +} + +void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) { + uint32_t uidx = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + Allocation *alloc = mRSProgram->mHal.state.constants[ct].get(); + if (!alloc) { + LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); + rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); + continue; + } + + const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); + const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + const char *fieldName = e->getFieldName(field); + // If this field is padding, skip it + if (fieldName[0] == '#') { + continue; + } + + uint32_t offset = e->getFieldOffsetBytes(field); + const float *fd = reinterpret_cast<const float *>(&data[offset]); + + int32_t slot = -1; + uint32_t arraySize = 1; + if (!isFragment) { + slot = sc->vtxUniformSlot(uidx); + arraySize = sc->vtxUniformSize(uidx); + } else { + slot = sc->fragUniformSlot(uidx); + arraySize = sc->fragUniformSize(uidx); + } + if (rsc->props.mLogShadersUniforms) { + LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); + } + uidx ++; + if (slot < 0) { + continue; + } + + if (rsc->props.mLogShadersUniforms) { + logUniform(f, fd, arraySize); + } + setUniform(rsc, f, fd, slot, arraySize); + } + } +} + +void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) { + + setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER); + setupTextures(rsc, sc); +} + +void RsdShader::initAttribAndUniformArray() { + mAttribCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.inputElements[ct].get(); + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mAttribCount ++; + } + } + } + + mUniformCount = 0; + for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { + const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement(); + + for (uint32_t field=0; field < elem->getFieldCount(); field++) { + if (elem->getFieldName(field)[0] != '#') { + mUniformCount ++; + } + } + } + mUniformCount += mRSProgram->mHal.state.texturesCount; + + if (mAttribCount) { + mAttribNames = new String8[mAttribCount]; + } + if (mUniformCount) { + mUniformNames = new String8[mUniformCount]; + mUniformArraySizes = new uint32_t[mUniformCount]; + } +} + +void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { + rsAssert(e->getFieldCount()); + for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { + const Element *ce = e->getField(ct); + if (ce->getFieldCount()) { + initAddUserElement(ce, names, arrayLengths, count, prefix); + } else if (e->getFieldName(ct)[0] != '#') { + String8 tmp(prefix); + tmp.append(e->getFieldName(ct)); + names[*count].setTo(tmp.string()); + if (arrayLengths) { + arrayLengths[*count] = e->getFieldArraySize(ct); + } + (*count)++; + } + } +} diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h new file mode 100644 index 0000000..63c4231 --- /dev/null +++ b/libs/rs/driver/rsdShader.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#ifndef ANDROID_RSD_SHADER_H +#define ANDROID_RSD_SHADER_H + +#include <utils/String8.h> + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Element; +class Context; +class Program; + +} +} + +class RsdShaderCache; + +#define RS_SHADER_ATTR "ATTRIB_" +#define RS_SHADER_UNI "UNI_" + +class RsdShader { +public: + + RsdShader(const android::renderscript::Program *p, uint32_t type, + const char * shaderText, uint32_t shaderLength); + virtual ~RsdShader(); + + bool createShader(); + + uint32_t getShaderID() const {return mShaderID;} + + uint32_t getAttribCount() const {return mAttribCount;} + uint32_t getUniformCount() const {return mUniformCount;} + const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];} + const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];} + uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];} + + android::String8 getGLSLInputString() const; + + bool isValid() const {return mIsValid;} + void forceDirty() const {mDirty = true;} + + bool loadShader(const android::renderscript::Context *); + void setup(const android::renderscript::Context *, RsdShaderCache *sc); + +protected: + + const android::renderscript::Program *mRSProgram; + bool mIsValid; + + // Applies to vertex and fragment shaders only + void appendUserConstants(); + void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment); + void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); + void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc); + void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex); + + void appendAttributes(); + void appendTextures(); + + void initAttribAndUniformArray(); + + mutable bool mDirty; + android::String8 mShader; + android::String8 mUserShader; + uint32_t mShaderID; + uint32_t mType; + + uint32_t mTextureCount; + uint32_t mAttribCount; + uint32_t mUniformCount; + android::String8 *mAttribNames; + android::String8 *mUniformNames; + uint32_t *mUniformArraySizes; + + int32_t mTextureUniformIndexStart; + + void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize ); + void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize ); + void initMemberVars(); + void init(); +}; + +#endif //ANDROID_RSD_SHADER_H + + + + diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp index e8d89c2..d11490c 100644 --- a/libs/rs/rsShaderCache.cpp +++ b/libs/rs/driver/rsdShaderCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -14,25 +14,31 @@ * limitations under the License. */ -#include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE +#include <rs_hal.h> +#include <rsContext.h> + +#include "rsdShader.h" +#include "rsdShaderCache.h" +#include "rsdGL.h" + #include <GLES/gl.h> #include <GLES2/gl2.h> -#endif //ANDROID_RS_SERIALIZE using namespace android; using namespace android::renderscript; -ShaderCache::ShaderCache() { +RsdShaderCache::RsdShaderCache() { mEntries.setCapacity(16); + mVertexDirty = true; + mFragmentDirty = true; } -ShaderCache::~ShaderCache() { +RsdShaderCache::~RsdShaderCache() { cleanupAll(); } -void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID, +void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID, UniformData *data, const char* logTag, UniformQueryData **uniformList, uint32_t uniListSize) { @@ -54,14 +60,14 @@ void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t l } } -void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) { +void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) { for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) { data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct)); data[ct].arraySize = prog->getUniformArraySize(ct); } } -bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) { +bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) { UniformData *data = mCurrent->vtxUniforms; for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { if (data[ct].slot >= 0 && data[ct].arraySize > 1) { @@ -77,7 +83,31 @@ bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) { return false; } -bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) { +bool RsdShaderCache::setup(const Context *rsc) { + if (!mVertexDirty && !mFragmentDirty) { + return true; + } + + if (!link(rsc)) { + return false; + } + + if (mFragmentDirty) { + mFragment->setup(rsc, this); + mFragmentDirty = false; + } + if (mVertexDirty) { + mVertex->setup(rsc, this); + mVertexDirty = false; + } + + return true; +} + +bool RsdShaderCache::link(const Context *rsc) { + + RsdShader *vtx = mVertex; + RsdShader *frag = mFragment; if (!vtx->getShaderID()) { vtx->loadShader(rsc); } @@ -89,7 +119,7 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag if (!vtx->getShaderID() || !frag->getShaderID()) { return false; } - //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); + //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); uint32_t entryCount = mEntries.size(); for (uint32_t ct = 0; ct < entryCount; ct ++) { if ((mEntries[ct]->vtx == vtx->getShaderID()) && @@ -98,13 +128,13 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGV("SC using program %i", mEntries[ct]->program); glUseProgram(mEntries[ct]->program); mCurrent = mEntries[ct]; - //LOGV("ShaderCache hit, using %i", ct); - rsc->checkError("ShaderCache::lookup (hit)"); + //LOGV("RsdShaderCache hit, using %i", ct); + rsdGLCheckError(rsc, "RsdShaderCache::link (hit)"); return true; } } - //LOGV("ShaderCache miss"); + //LOGV("RsdShaderCache miss"); //LOGE("e0 %x", glGetError()); ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(), vtx->getUniformCount(), @@ -120,12 +150,10 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGE("e1 %x", glGetError()); glAttachShader(pgm, frag->getShaderID()); - if (!vtx->isUserProgram()) { - glBindAttribLocation(pgm, 0, "ATTRIB_position"); - glBindAttribLocation(pgm, 1, "ATTRIB_color"); - glBindAttribLocation(pgm, 2, "ATTRIB_normal"); - glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); - } + glBindAttribLocation(pgm, 0, "ATTRIB_position"); + glBindAttribLocation(pgm, 1, "ATTRIB_color"); + glBindAttribLocation(pgm, 2, "ATTRIB_normal"); + glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); //LOGE("e2 %x", glGetError()); glLinkProgram(pgm); @@ -203,11 +231,12 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //LOGV("SC made program %i", e->program); glUseProgram(e->program); - rsc->checkError("ShaderCache::lookup (miss)"); + rsdGLCheckError(rsc, "RsdShaderCache::link (miss)"); + return true; } -int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { +int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const { for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { if (attrName == mCurrent->vtxAttrs[ct].name) { return mCurrent->vtxAttrs[ct].slot; @@ -216,7 +245,7 @@ int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { return -1; } -void ShaderCache::cleanupVertex(uint32_t id) { +void RsdShaderCache::cleanupVertex(uint32_t id) { int32_t numEntries = (int32_t)mEntries.size(); for (int32_t ct = 0; ct < numEntries; ct ++) { if (mEntries[ct]->vtx == id) { @@ -230,7 +259,7 @@ void ShaderCache::cleanupVertex(uint32_t id) { } } -void ShaderCache::cleanupFragment(uint32_t id) { +void RsdShaderCache::cleanupFragment(uint32_t id) { int32_t numEntries = (int32_t)mEntries.size(); for (int32_t ct = 0; ct < numEntries; ct ++) { if (mEntries[ct]->frag == id) { @@ -244,7 +273,7 @@ void ShaderCache::cleanupFragment(uint32_t id) { } } -void ShaderCache::cleanupAll() { +void RsdShaderCache::cleanupAll() { for (uint32_t ct=0; ct < mEntries.size(); ct++) { glDeleteProgram(mEntries[ct]->program); free(mEntries[ct]); diff --git a/libs/rs/rsShaderCache.h b/libs/rs/driver/rsdShaderCache.h index 3540366..17ee3e8 100644 --- a/libs/rs/rsShaderCache.h +++ b/libs/rs/driver/rsdShaderCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -14,38 +14,59 @@ * limitations under the License. */ -#ifndef ANDROID_SHADER_CACHE_H -#define ANDROID_SHADER_CACHE_H +#ifndef ANDROID_RSD_SHADER_CACHE_H +#define ANDROID_RSD_SHADER_CACHE_H - -#include "rsObjectBase.h" -#include "rsVertexArray.h" - -// --------------------------------------------------------------------------- namespace android { namespace renderscript { +class Context; + +} +} + +#include <utils/String8.h> +#include <utils/Vector.h> +class RsdShader; + +// --------------------------------------------------------------------------- // An element is a group of Components that occupies one cell in a structure. -class ShaderCache { +class RsdShaderCache { public: - ShaderCache(); - virtual ~ShaderCache(); + RsdShaderCache(); + virtual ~RsdShaderCache(); + + void setActiveVertex(RsdShader *pv) { + mVertexDirty = true; + mVertex = pv; + } - bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *); + void setActiveFragment(RsdShader *pf) { + mFragmentDirty = true; + mFragment = pf; + } + + bool setup(const android::renderscript::Context *rsc); void cleanupVertex(uint32_t id); void cleanupFragment(uint32_t id); void cleanupAll(); - int32_t vtxAttribSlot(const String8 &attrName) const; + int32_t vtxAttribSlot(const android::String8 &attrName) const; int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;} uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;} int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;} uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;} protected: + bool link(const android::renderscript::Context *rsc); + bool mFragmentDirty; + bool mVertexDirty; + RsdShader *mVertex; + RsdShader *mFragment; + struct UniformQueryData { char *name; uint32_t nameLength; @@ -111,21 +132,19 @@ protected: UniformData *vtxUniforms; UniformData *fragUniforms; }; - Vector<ProgramEntry*> mEntries; + android::Vector<ProgramEntry*> mEntries; ProgramEntry *mCurrent; - bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag); - void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data); - void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID, + bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag); + void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data); + void updateUniformArrayData(const android::renderscript::Context *rsc, + RsdShader *prog, uint32_t linkedID, UniformData *data, const char* logTag, UniformQueryData **uniformList, uint32_t uniListSize); }; - -} -} -#endif //ANDROID_SHADER_CACHE_H +#endif //ANDROID_RSD_SHADER_CACHE_H diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp index 354ee89..62ec107 100644 --- a/libs/rs/rsVertexArray.cpp +++ b/libs/rs/driver/rsdVertexArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -14,28 +14,33 @@ * limitations under the License. */ -#include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE +#include <rs_hal.h> +#include <rsContext.h> + #include <GLES/gl.h> #include <GLES2/gl2.h> -#endif + +#include "rsdGL.h" +#include "rsdCore.h" +#include "rsdVertexArray.h" +#include "rsdShaderCache.h" using namespace android; using namespace android::renderscript; -VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) { +RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) { mAttribs = attribs; mCount = numAttribs; } -VertexArray::~VertexArray() { +RsdVertexArray::~RsdVertexArray() { } -VertexArray::Attrib::Attrib() { +RsdVertexArray::Attrib::Attrib() { clear(); } -void VertexArray::Attrib::clear() { +void RsdVertexArray::Attrib::clear() { buffer = 0; offset = 0; type = 0; @@ -46,7 +51,7 @@ void VertexArray::Attrib::clear() { name.setTo(""); } -void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, +void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name) { clear(); @@ -58,7 +63,7 @@ void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, this->name.setTo(name); } -void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { +void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const { if (idx == 0) { LOGV("Starting vertex attribute binding"); } @@ -74,11 +79,15 @@ void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { mAttribs[idx].offset); } -void VertexArray::setupGL2(const Context *rsc, - class VertexArrayState *state, - ShaderCache *sc) const { - rsc->checkError("VertexArray::setupGL2 start"); +void RsdVertexArray::setup(const Context *rsc) const { + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + RsdVertexArrayState *state = dc->gl.vertexArrayState; + RsdShaderCache *sc = dc->gl.shaderCache; + + rsdGLCheckError(rsc, "RsdVertexArray::setup start"); uint32_t maxAttrs = state->mAttrsEnabledSize; + for (uint32_t ct=1; ct < maxAttrs; ct++) { if(state->mAttrsEnabled[ct]) { glDisableVertexAttribArray(ct); @@ -86,7 +95,7 @@ void VertexArray::setupGL2(const Context *rsc, } } - rsc->checkError("VertexArray::setupGL2 disabled"); + rsdGLCheckError(rsc, "RsdVertexArray::setup disabled"); for (uint32_t ct=0; ct < mCount; ct++) { int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name); if (rsc->props.mLogShadersAttr) { @@ -105,22 +114,22 @@ void VertexArray::setupGL2(const Context *rsc, mAttribs[ct].stride, mAttribs[ct].ptr + mAttribs[ct].offset); } - rsc->checkError("VertexArray::setupGL2 done"); + rsdGLCheckError(rsc, "RsdVertexArray::setup done"); } //////////////////////////////////////////// -VertexArrayState::VertexArrayState() { +RsdVertexArrayState::RsdVertexArrayState() { mAttrsEnabled = NULL; mAttrsEnabledSize = 0; } -VertexArrayState::~VertexArrayState() { +RsdVertexArrayState::~RsdVertexArrayState() { if (mAttrsEnabled) { delete[] mAttrsEnabled; mAttrsEnabled = NULL; } } -void VertexArrayState::init(Context *rsc) { - mAttrsEnabledSize = rsc->getMaxVertexAttributes(); +void RsdVertexArrayState::init(uint32_t maxAttrs) { + mAttrsEnabledSize = maxAttrs; mAttrsEnabled = new bool[mAttrsEnabledSize]; for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) { mAttrsEnabled[ct] = false; diff --git a/libs/rs/rsVertexArray.h b/libs/rs/driver/rsdVertexArray.h index 45d9e82..3e807a3 100644 --- a/libs/rs/rsVertexArray.h +++ b/libs/rs/driver/rsdVertexArray.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -14,20 +14,21 @@ * limitations under the License. */ -#ifndef ANDROID_VERTEX_ARRAY_H -#define ANDROID_VERTEX_ARRAY_H +#ifndef ANDROID_RSD_VERTEX_ARRAY_H +#define ANDROID_RSD_VERTEX_ARRAY_H - -#include "rsObjectBase.h" - -// --------------------------------------------------------------------------- namespace android { namespace renderscript { -class ShaderCache; +class Context; + +} +} + +#include <utils/String8.h> // An element is a group of Components that occupies one cell in a structure. -class VertexArray { +class RsdVertexArray { public: class Attrib { public: @@ -38,17 +39,17 @@ public: uint32_t size; uint32_t stride; bool normalized; - String8 name; + android::String8 name; Attrib(); void clear(); void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name); }; - VertexArray(const Attrib *attribs, uint32_t numAttribs); - virtual ~VertexArray(); + RsdVertexArray(const Attrib *attribs, uint32_t numAttribs); + virtual ~RsdVertexArray(); - void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const; + void setup(const android::renderscript::Context *rsc) const; void logAttrib(uint32_t idx, uint32_t slot) const; protected: @@ -61,20 +62,18 @@ protected: }; -class VertexArrayState { +class RsdVertexArrayState { public: - VertexArrayState(); - ~VertexArrayState(); - void init(Context *); + RsdVertexArrayState(); + ~RsdVertexArrayState(); + void init(uint32_t maxAttrs); bool *mAttrsEnabled; uint32_t mAttrsEnabledSize; }; -} -} -#endif //ANDROID_VERTEX_ARRAY_H +#endif //ANDROID_RSD_VERTEX_ARRAY_H diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 7e23cec..87d764d 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -1,6 +1,72 @@ +ContextDestroy { + direct +} + +ContextGetMessage { + direct + param void *data + param size_t *receiveLen + param uint32_t *usrID + ret RsMessageToClientType +} + +ContextPeekMessage { + direct + param size_t *receiveLen + param uint32_t *usrID + ret RsMessageToClientType +} + +ContextInitToClient { + direct +} + +ContextDeinitToClient { + direct +} + +TypeCreate { + direct + param RsElement e + param uint32_t dimX + param uint32_t dimY + param uint32_t dimZ + param bool mips + param bool faces + ret RsType +} + +AllocationCreateTyped { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param uint32_t usages + ret RsAllocation +} + +AllocationCreateFromBitmap { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param const void *data + param uint32_t usages + ret RsAllocation +} + +AllocationCubeCreateFromBitmap { + direct + param RsType vtype + param RsAllocationMipmapControl mips + param const void *data + param uint32_t usages + ret RsAllocation +} + + + ContextFinish { - handcodeApi + sync } ContextBindRootScript { @@ -36,7 +102,7 @@ ContextResume { ContextSetSurface { param uint32_t width param uint32_t height - param ANativeWindow *sur + param RsNativeWindow sur } ContextDump { @@ -51,9 +117,8 @@ ContextDestroyWorker { } AssignName { - param void *obj + param RsObjectBase obj param const char *name - param size_t len } ObjDestroy { @@ -69,10 +134,8 @@ ElementCreate { } ElementCreate2 { - param size_t count param const RsElement * elements param const char ** names - param const size_t * nameLengths param const uint32_t * arraySize ret RsElement } @@ -80,7 +143,6 @@ ElementCreate2 { AllocationCopyToBitmap { param RsAllocation alloc param void * data - param size_t dataLen } @@ -90,9 +152,6 @@ Allocation1DData { param uint32_t lod param uint32_t count param const void *data - param uint32_t bytes - handcodeApi - togglePlay } Allocation1DElementData { @@ -101,9 +160,6 @@ Allocation1DElementData { param uint32_t lod param const void *data param uint32_t comp_offset - param uint32_t bytes - handcodeApi - togglePlay } Allocation2DData { @@ -115,7 +171,6 @@ Allocation2DData { param uint32_t w param uint32_t h param const void *data - param uint32_t bytes } Allocation2DElementData { @@ -126,7 +181,6 @@ Allocation2DElementData { param RsAllocationCubemapFace face param const void *data param uint32_t element_offset - param uint32_t bytes } AllocationGenerateMipmaps { @@ -155,24 +209,15 @@ AllocationResize2D { param uint32_t dimY } -SamplerBegin { - } - -SamplerSet { - param RsSamplerParam p - param RsSamplerValue value - } - -SamplerSet2 { - param RsSamplerParam p - param float value - } - SamplerCreate { - ret RsSampler - } - - + param RsSamplerValue magFilter + param RsSamplerValue minFilter + param RsSamplerValue wrapS + param RsSamplerValue wrapT + param RsSamplerValue wrapR + param float mAniso + ret RsSampler +} ScriptBindAllocation { param RsScript vtm @@ -180,18 +225,11 @@ ScriptBindAllocation { param uint32_t slot } - -ScriptCBegin { - } - - ScriptSetTimeZone { param RsScript s param const char * timeZone - param uint32_t length } - ScriptInvoke { param RsScript s param uint32_t slot @@ -201,11 +239,16 @@ ScriptInvokeV { param RsScript s param uint32_t slot param const void * data - param uint32_t dataLen - handcodeApi - togglePlay } +ScriptForEach { + param RsScript s + param uint32_t slot + param RsAllocation ain + param RsAllocation aout + param const void * usr +} + ScriptSetVarI { param RsScript s param uint32_t slot @@ -240,55 +283,27 @@ ScriptSetVarV { param RsScript s param uint32_t slot param const void * data - param uint32_t dataLen - handcodeApi - togglePlay } -ScriptCSetText { - param const char * text - param uint32_t length - } - ScriptCCreate { - param const char * packageName param const char * resName param const char * cacheDir + param const char * text ret RsScript } -ProgramStoreBegin { - param RsElement in - param RsElement out - } - -ProgramStoreColorMask { - param bool r - param bool g - param bool b - param bool a - } - -ProgramStoreBlendFunc { +ProgramStoreCreate { + param bool colorMaskR + param bool colorMaskG + param bool colorMaskB + param bool colorMaskA + param bool depthMask + param bool ditherEnable param RsBlendSrcFunc srcFunc param RsBlendDstFunc destFunc - } - -ProgramStoreDepthMask { - param bool enable -} - -ProgramStoreDither { - param bool enable -} - -ProgramStoreDepthFunc { - param RsDepthFunc func -} - -ProgramStoreCreate { + param RsDepthFunc depthFunc ret RsProgramStore } @@ -296,19 +311,11 @@ ProgramRasterCreate { param bool pointSmooth param bool lineSmooth param bool pointSprite + param float lineWidth + param RsCullMode cull ret RsProgramRaster } -ProgramRasterSetLineWidth { - param RsProgramRaster pr - param float lw -} - -ProgramRasterSetCullMode { - param RsProgramRaster pr - param RsCullMode mode -} - ProgramBindConstants { param RsProgram vp param uint32_t slot @@ -330,17 +337,13 @@ ProgramBindSampler { ProgramFragmentCreate { param const char * shaderText - param uint32_t shaderLength param const uint32_t * params - param uint32_t paramLength ret RsProgramFragment } ProgramVertexCreate { param const char * shaderText - param uint32_t shaderLength param const uint32_t * params - param uint32_t paramLength ret RsProgramVertex } @@ -355,41 +358,13 @@ FontCreateFromMemory { param const char *name param float fontSize param uint32_t dpi - param const void *data - param uint32_t dataLen + param const void *data ret RsFont } MeshCreate { + param RsAllocation *vtx + param RsAllocation *idx + param uint32_t *primType ret RsMesh - param uint32_t vtxCount - param uint32_t idxCount - } - -MeshBindIndex { - param RsMesh mesh - param RsAllocation idx - param uint32_t primType - param uint32_t slot } - -MeshBindVertex { - param RsMesh mesh - param RsAllocation vtx - param uint32_t slot - } - -MeshInitVertexAttribs { - param RsMesh mesh - } - -AnimationCreate { - param const float *inValues - param const float *outValues - param uint32_t valueCount - param RsAnimationInterpolation interp - param RsAnimationEdge pre - param RsAnimationEdge post - ret RsAnimation - } - diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index ec03a15..bff3660 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -15,11 +15,8 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES2/gl2.h> -#include <GLES/glext.h> -#endif //ANDROID_RS_SERIALIZE +#include "rs_hal.h" + using namespace android; using namespace android::renderscript; @@ -27,308 +24,70 @@ using namespace android::renderscript; Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages, RsAllocationMipmapControl mc) : ObjectBase(rsc) { - init(rsc, type); - - mUsageFlags = usages; - mMipmapControl = mc; - - allocScriptMemory(); - if (mType->getElement()->getHasReferences()) { - memset(mPtr, 0, mType->getSizeBytes()); - } - if (!mPtr) { - LOGE("Allocation::Allocation, alloc failure"); - } -} - - -void Allocation::init(Context *rsc, const Type *type) { - mPtr = NULL; - - mCpuWrite = false; - mCpuRead = false; - mGpuWrite = false; - mGpuRead = false; - - mReadWriteRatio = 0; - mUpdateSize = 0; - mUsageFlags = 0; - mMipmapControl = RS_ALLOCATION_MIPMAP_NONE; - - mTextureID = 0; - mBufferID = 0; - mUploadDefered = false; - - mUserBitmapCallback = NULL; - mUserBitmapCallbackData = NULL; - - mType.set(type); - rsAssert(type); - - mPtr = NULL; -} - -Allocation::~Allocation() { - if (mUserBitmapCallback != NULL) { - mUserBitmapCallback(mUserBitmapCallbackData); - mPtr = NULL; - } - freeScriptMemory(); -#ifndef ANDROID_RS_SERIALIZE - if (mBufferID) { - // Causes a SW crash.... - //LOGV(" mBufferID %i", mBufferID); - //glDeleteBuffers(1, &mBufferID); - //mBufferID = 0; - } - if (mTextureID) { - glDeleteTextures(1, &mTextureID); - mTextureID = 0; - } -#endif //ANDROID_RS_SERIALIZE -} -void Allocation::setCpuWritable(bool) { -} - -void Allocation::setGpuWritable(bool) { -} - -void Allocation::setCpuReadable(bool) { -} - -void Allocation::setGpuReadable(bool) { -} + memset(&mHal, 0, sizeof(mHal)); + mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE; + mHal.state.usageFlags = usages; + mHal.state.mipmapControl = mc; -bool Allocation::fixAllocation() { - return false; + mHal.state.type.set(type); + updateCache(); } -void Allocation::deferedUploadToTexture(const Context *rsc) { - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; - mUploadDefered = true; -} +Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages, + RsAllocationMipmapControl mc) { + Allocation *a = new Allocation(rsc, type, usages, mc); -uint32_t Allocation::getGLTarget() const { -#ifndef ANDROID_RS_SERIALIZE - if (getIsTexture()) { - if (mType->getDimFaces()) { - return GL_TEXTURE_CUBE_MAP; - } else { - return GL_TEXTURE_2D; - } - } - if (getIsBufferObject()) { - return GL_ARRAY_BUFFER; + if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) { + rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure"); + delete a; + return NULL; } -#endif //ANDROID_RS_SERIALIZE - return 0; + return a; } -void Allocation::allocScriptMemory() { - rsAssert(!mPtr); - mPtr = malloc(mType->getSizeBytes()); +void Allocation::updateCache() { + const Type *type = mHal.state.type.get(); + mHal.state.dimensionX = type->getDimX(); + mHal.state.dimensionY = type->getDimY(); + mHal.state.dimensionZ = type->getDimZ(); + mHal.state.hasFaces = type->getDimFaces(); + mHal.state.hasMipmaps = type->getDimLOD(); + mHal.state.elementSizeBytes = type->getElementSizeBytes(); + mHal.state.hasReferences = mHal.state.type->getElement()->getHasReferences(); } -void Allocation::freeScriptMemory() { - if (mPtr) { - free(mPtr); - mPtr = NULL; - } +Allocation::~Allocation() { + mRSC->mHal.funcs.allocation.destroy(mRSC, this); } - void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) { - rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT); - - if (getIsTexture()) { - uploadToTexture(rsc); - } - if (getIsBufferObject()) { - uploadToBufferObject(rsc); - } - - mUploadDefered = false; -} - -void Allocation::uploadToTexture(const Context *rsc) { -#ifndef ANDROID_RS_SERIALIZE - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE; - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); - - if (!type || !format) { - return; - } - - if (!mPtr) { - return; - } - - bool isFirstUpload = false; - - if (!mTextureID) { - glGenTextures(1, &mTextureID); - - if (!mTextureID) { - // This should not happen, however, its likely the cause of the - // white sqare bug. - // Force a crash to 1: restart the app, 2: make sure we get a bugreport. - LOGE("Upload to texture failed to gen mTextureID"); - rsc->dumpDebug(); - mUploadDefered = true; - return; - } - isFirstUpload = true; - } - - upload2DTexture(isFirstUpload); - - if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { - freeScriptMemory(); - } - - rsc->checkError("Allocation::uploadToTexture"); -#endif //ANDROID_RS_SERIALIZE -} - -#ifndef ANDROID_RS_SERIALIZE -const static GLenum gFaceOrder[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z -}; -#endif //ANDROID_RS_SERIALIZE - -void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, - uint32_t lod, RsAllocationCubemapFace face, - uint32_t w, uint32_t h) { -#ifndef ANDROID_RS_SERIALIZE - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); - GLenum target = (GLenum)getGLTarget(); - rsAssert(mTextureID); - glBindTexture(target, mTextureID); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - GLenum t = GL_TEXTURE_2D; - if (mType->getDimFaces()) { - t = gFaceOrder[face]; - } - glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr); -#endif //ANDROID_RS_SERIALIZE -} - -void Allocation::upload2DTexture(bool isFirstUpload) { -#ifndef ANDROID_RS_SERIALIZE - GLenum type = mType->getElement()->getComponent().getGLType(); - GLenum format = mType->getElement()->getComponent().getGLFormat(); - - GLenum target = (GLenum)getGLTarget(); - glBindTexture(target, mTextureID); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - uint32_t faceCount = 1; - if (mType->getDimFaces()) { - faceCount = 6; - } - - for (uint32_t face = 0; face < faceCount; face ++) { - for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) { - const uint8_t *p = (const uint8_t *)mPtr; - p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); - - GLenum t = GL_TEXTURE_2D; - if (mType->getDimFaces()) { - t = gFaceOrder[face]; - } - - if (isFirstUpload) { - glTexImage2D(t, lod, format, - mType->getLODDimX(lod), mType->getLODDimY(lod), - 0, format, type, p); - } else { - glTexSubImage2D(t, lod, 0, 0, - mType->getLODDimX(lod), mType->getLODDimY(lod), - format, type, p); - } - } - } - - if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { - glGenerateMipmap(target); - } -#endif //ANDROID_RS_SERIALIZE -} - -void Allocation::deferedUploadToBufferObject(const Context *rsc) { - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; - mUploadDefered = true; -} - -void Allocation::uploadToBufferObject(const Context *rsc) { -#ifndef ANDROID_RS_SERIALIZE - rsAssert(!mType->getDimY()); - rsAssert(!mType->getDimZ()); - - mUsageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; - - if (!mBufferID) { - glGenBuffers(1, &mBufferID); - } - if (!mBufferID) { - LOGE("Upload to buffer object failed"); - mUploadDefered = true; - return; - } - GLenum target = (GLenum)getGLTarget(); - glBindBuffer(target, mBufferID); - glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); - glBindBuffer(target, 0); - rsc->checkError("Allocation::uploadToBufferObject"); -#endif //ANDROID_RS_SERIALIZE -} - -void Allocation::uploadCheck(Context *rsc) { - if (mUploadDefered) { - syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT); - } + rsc->mHal.funcs.allocation.syncAll(rsc, this, src); } void Allocation::read(void *data) { - memcpy(data, mPtr, mType->getSizeBytes()); + memcpy(data, getPtr(), mHal.state.type->getSizeBytes()); } void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); - ptr += eSize * xoff; - uint32_t size = count * eSize; - - if (size != sizeBytes) { - LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes); - mType->dumpLOGV("type info"); - return; - } + const uint32_t eSize = mHal.state.type->getElementSizeBytes(); - if (mType->getElement()->getHasReferences()) { - incRefs(data, count); - decRefs(ptr, count); + if ((count * eSize) != sizeBytes) { + LOGE("Allocation::subData called with mismatched size expected %i, got %i", + (count * eSize), sizeBytes); + mHal.state.type->dumpLOGV("type info"); + return; } - memcpy(ptr, data, size); - sendDirty(); - mUploadDefered = true; + rsc->mHal.funcs.allocation.data1D(rsc, this, xoff, lod, count, data, sizeBytes); + sendDirty(rsc); } void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint32_t lineSize = eSize * w; - uint32_t destW = mType->getDimX(); + const uint32_t eSize = mHal.state.elementSizeBytes; + const uint32_t lineSize = eSize * w; //LOGE("data2d %p, %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes); @@ -338,26 +97,8 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, return; } - if (mPtr) { - const uint8_t *src = static_cast<const uint8_t *>(data); - uint8_t *dst = static_cast<uint8_t *>(mPtr); - dst += mType->getLODFaceOffset(lod, face, xoff, yoff); - - //LOGE(" %p %p %i ", dst, src, eSize); - for (uint32_t line=yoff; line < (yoff+h); line++) { - if (mType->getElement()->getHasReferences()) { - incRefs(src, w); - decRefs(dst, w); - } - memcpy(dst, src, lineSize); - src += lineSize; - dst += destW * eSize; - } - sendDirty(); - mUploadDefered = true; - } else { - update2DTexture(data, xoff, yoff, lod, face, w, h); - } + rsc->mHal.funcs.allocation.data2D(rsc, this, xoff, yoff, lod, face, w, h, data, sizeBytes); + sendDirty(rsc); } void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, @@ -367,67 +108,54 @@ void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, void Allocation::elementData(Context *rsc, uint32_t x, const void *data, uint32_t cIdx, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); - ptr += eSize * x; + uint32_t eSize = mHal.state.elementSizeBytes; - if (cIdx >= mType->getElement()->getFieldCount()) { + if (cIdx >= mHal.state.type->getElement()->getFieldCount()) { LOGE("Error Allocation::subElementData component %i out of range.", cIdx); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range."); return; } - if (x >= mType->getDimX()) { + if (x >= mHal.state.dimensionX) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - const Element * e = mType->getElement()->getField(cIdx); - ptr += mType->getElement()->getFieldOffsetBytes(cIdx); - + const Element * e = mHal.state.type->getElement()->getField(cIdx); if (sizeBytes != e->getSizeBytes()) { LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size."); return; } - if (e->getHasReferences()) { - e->incRefs(data); - e->decRefs(ptr); - } - - memcpy(ptr, data, sizeBytes); - sendDirty(); - mUploadDefered = true; + rsc->mHal.funcs.allocation.elementData1D(rsc, this, x, data, cIdx, sizeBytes); + sendDirty(rsc); } void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, const void *data, uint32_t cIdx, uint32_t sizeBytes) { - uint32_t eSize = mType->getElementSizeBytes(); - uint8_t * ptr = static_cast<uint8_t *>(mPtr); - ptr += eSize * (x + y * mType->getDimX()); + uint32_t eSize = mHal.state.elementSizeBytes; - if (x >= mType->getDimX()) { + if (x >= mHal.state.dimensionX) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - if (y >= mType->getDimY()) { + if (y >= mHal.state.dimensionY) { LOGE("Error Allocation::subElementData X offset %i out of range.", x); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range."); return; } - if (cIdx >= mType->getElement()->getFieldCount()) { + if (cIdx >= mHal.state.type->getElement()->getFieldCount()) { LOGE("Error Allocation::subElementData component %i out of range.", cIdx); rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range."); return; } - const Element * e = mType->getElement()->getField(cIdx); - ptr += mType->getElement()->getFieldOffsetBytes(cIdx); + const Element * e = mHal.state.type->getElement()->getField(cIdx); if (sizeBytes != e->getSizeBytes()) { LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes()); @@ -435,24 +163,15 @@ void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y, return; } - if (e->getHasReferences()) { - e->incRefs(data); - e->decRefs(ptr); - } - - memcpy(ptr, data, sizeBytes); - sendDirty(); - mUploadDefered = true; + rsc->mHal.funcs.allocation.elementData2D(rsc, this, x, y, data, cIdx, sizeBytes); + sendDirty(rsc); } void Allocation::addProgramToDirty(const Program *p) { -#ifndef ANDROID_RS_SERIALIZE mToDirtyList.push(p); -#endif //ANDROID_RS_SERIALIZE } void Allocation::removeProgramToDirty(const Program *p) { -#ifndef ANDROID_RS_SERIALIZE for (size_t ct=0; ct < mToDirtyList.size(); ct++) { if (mToDirtyList[ct] == p) { mToDirtyList.removeAt(ct); @@ -460,7 +179,6 @@ void Allocation::removeProgramToDirty(const Program *p) { } } rsAssert(0); -#endif //ANDROID_RS_SERIALIZE } void Allocation::dumpLOGV(const char *prefix) const { @@ -468,15 +186,12 @@ void Allocation::dumpLOGV(const char *prefix) const { String8 s(prefix); s.append(" type "); - if (mType.get()) { - mType->dumpLOGV(s.string()); + if (mHal.state.type.get()) { + mHal.state.type->dumpLOGV(s.string()); } - LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i", - prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead); - - LOGV("%s allocation mUsageFlags=0x04%x, mMipmapControl=0x%04x, mTextureID=%i, mBufferID=%i", - prefix, mUsageFlags, mMipmapControl, mTextureID, mBufferID); + LOGV("%s allocation ptr=%p mUsageFlags=0x04%x, mMipmapControl=0x%04x", + prefix, getPtr(), mHal.state.usageFlags, mHal.state.mipmapControl); } void Allocation::serialize(OStream *stream) const { @@ -488,13 +203,13 @@ void Allocation::serialize(OStream *stream) const { // First thing we need to serialize is the type object since it will be needed // to initialize the class - mType->serialize(stream); + mHal.state.type->serialize(stream); - uint32_t dataSize = mType->getSizeBytes(); + uint32_t dataSize = mHal.state.type->getSizeBytes(); // Write how much data we are storing stream->addU32(dataSize); // Now write the data - stream->addByteArray(mPtr, dataSize); + stream->addByteArray(getPtr(), dataSize); } Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { @@ -522,7 +237,7 @@ Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { return NULL; } - Allocation *alloc = new Allocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT); + Allocation *alloc = Allocation::createAllocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT); alloc->setName(name.string(), name.size()); uint32_t count = dataSize / type->getElementSizeBytes(); @@ -534,17 +249,16 @@ Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) { return alloc; } -void Allocation::sendDirty() const { -#ifndef ANDROID_RS_SERIALIZE +void Allocation::sendDirty(const Context *rsc) const { for (size_t ct=0; ct < mToDirtyList.size(); ct++) { mToDirtyList[ct]->forceDirty(); } -#endif //ANDROID_RS_SERIALIZE + mRSC->mHal.funcs.allocation.markDirty(rsc, this); } void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const { const uint8_t *p = static_cast<const uint8_t *>(ptr); - const Element *e = mType->getElement(); + const Element *e = mHal.state.type->getElement(); uint32_t stride = e->getSizeBytes(); p += stride * startOff; @@ -557,7 +271,7 @@ void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const { void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const { const uint8_t *p = static_cast<const uint8_t *>(ptr); - const Element *e = mType->getElement(); + const Element *e = mHal.state.type->getElement(); uint32_t stride = e->getSizeBytes(); p += stride * startOff; @@ -572,24 +286,18 @@ void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff } void Allocation::resize1D(Context *rsc, uint32_t dimX) { - Type *t = mType->cloneAndResize1D(rsc, dimX); - - uint32_t oldDimX = mType->getDimX(); + uint32_t oldDimX = mHal.state.dimensionX; if (dimX == oldDimX) { return; } + Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX); if (dimX < oldDimX) { - decRefs(mPtr, oldDimX - dimX, dimX); + decRefs(getPtr(), oldDimX - dimX, dimX); } - mPtr = realloc(mPtr, t->getSizeBytes()); - - if (dimX > oldDimX) { - const Element *e = mType->getElement(); - uint32_t stride = e->getSizeBytes(); - memset(((uint8_t *)mPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); - } - mType.set(t); + rsc->mHal.funcs.allocation.resize(rsc, this, t, mHal.state.hasReferences); + mHal.state.type.set(t); + updateCache(); } void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { @@ -598,22 +306,11 @@ void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { ///////////////// // -#ifndef ANDROID_RS_SERIALIZE - -static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va); namespace android { namespace renderscript { -void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel) { - Allocation *alloc = static_cast<Allocation *>(va); - alloc->deferedUploadToTexture(rsc); -} - -void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va) { - Allocation *alloc = static_cast<Allocation *>(va); - alloc->deferedUploadToBufferObject(rsc); -} +static void AllocationGenerateScriptMips(RsContext con, RsAllocation va); static void mip565(const Adapter2D &out, const Adapter2D &in) { uint32_t w = out.getDimX(); @@ -685,13 +382,13 @@ static void mip(const Adapter2D &out, const Adapter2D &in) { void rsi_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType src) { Allocation *a = static_cast<Allocation *>(va); + a->sendDirty(rsc); a->syncAll(rsc, src); - a->sendDirty(); } void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) { Allocation *texAlloc = static_cast<Allocation *>(va); - rsaAllocationGenerateScriptMips(rsc, texAlloc); + AllocationGenerateScriptMips(rsc, texAlloc); } void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) { @@ -708,30 +405,30 @@ void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_ } void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod, - uint32_t count, const void *data, uint32_t sizeBytes) { + uint32_t count, const void *data, size_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); a->data(rsc, xoff, lod, count, data, sizeBytes); } void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face, - const void *data, uint32_t eoff, uint32_t sizeBytes) { + const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped Allocation *a = static_cast<Allocation *>(va); a->elementData(rsc, x, y, data, eoff, sizeBytes); } void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod, - const void *data, uint32_t eoff, uint32_t sizeBytes) { + const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped Allocation *a = static_cast<Allocation *>(va); a->elementData(rsc, x, data, eoff, sizeBytes); } void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, - uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { + uint32_t w, uint32_t h, const void *data, size_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes); } -void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) { +void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data, size_t data_length) { Allocation *a = static_cast<Allocation *>(va); a->read(data); } @@ -746,10 +443,7 @@ void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32 a->resize2D(rsc, dimX, dimY); } -} -} - -static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) { +static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) { Context *rsc = static_cast<Context *>(con); Allocation *texAlloc = static_cast<Allocation *>(va); uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1; @@ -766,30 +460,23 @@ static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) { } } -const void * rsaAllocationGetType(RsContext con, RsAllocation va) { - Allocation *a = static_cast<Allocation *>(va); - a->getType()->incUserRef(); - - return a->getType(); -} - -RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - uint32_t usages) { - Context *rsc = static_cast<Context *>(con); - Allocation * alloc = new Allocation(rsc, static_cast<Type *>(vtype), usages, mips); +RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype, + RsAllocationMipmapControl mips, + uint32_t usages) { + Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips); + if (!alloc) { + return NULL; + } alloc->incUserRef(); return alloc; } - -RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages) { - Context *rsc = static_cast<Context *>(con); +RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype, + RsAllocationMipmapControl mips, + const void *data, size_t data_length, uint32_t usages) { Type *t = static_cast<Type *>(vtype); - RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, vtype, mips, usages); + RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages); Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); if (texAlloc == NULL) { LOGE("Memory allocation failure"); @@ -798,23 +485,22 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes()); if (mips == RS_ALLOCATION_MIPMAP_FULL) { - rsaAllocationGenerateScriptMips(rsc, texAlloc); + AllocationGenerateScriptMips(rsc, texAlloc); } - texAlloc->deferedUploadToTexture(rsc); + texAlloc->sendDirty(rsc); return texAlloc; } -RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, - RsAllocationMipmapControl mips, - const void *data, uint32_t usages) { - Context *rsc = static_cast<Context *>(con); +RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype, + RsAllocationMipmapControl mips, + const void *data, size_t data_length, uint32_t usages) { Type *t = static_cast<Type *>(vtype); // Cubemap allocation's faces should be Width by Width each. // Source data should have 6 * Width by Width pixels // Error checking is done in the java layer - RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, t, mips, usages); + RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages); Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); if (texAlloc == NULL) { LOGE("Memory allocation failure"); @@ -839,11 +525,19 @@ RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, } if (mips == RS_ALLOCATION_MIPMAP_FULL) { - rsaAllocationGenerateScriptMips(rsc, texAlloc); + AllocationGenerateScriptMips(rsc, texAlloc); } - texAlloc->deferedUploadToTexture(rsc); + texAlloc->sendDirty(rsc); return texAlloc; } -#endif //ANDROID_RS_SERIALIZE +} +} + +const void * rsaAllocationGetType(RsContext con, RsAllocation va) { + Allocation *a = static_cast<Allocation *>(va); + a->getType()->incUserRef(); + + return a->getType(); +} diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index 4f5d5a8..f538dd1 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -29,33 +29,44 @@ class Allocation : public ObjectBase { // The graphics equilivent of malloc. The allocation contains a structure of elements. public: - Allocation(Context *rsc, const Type *, uint32_t usages, - RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE); - + struct Hal { + void * drv; + + struct State { + ObjectBaseRef<const Type> type; + + uint32_t usageFlags; + RsAllocationMipmapControl mipmapControl; + + // Cached fields from the Type and Element + // to prevent pointer chasing in critical loops. + uint32_t dimensionX; + uint32_t dimensionY; + uint32_t dimensionZ; + uint32_t elementSizeBytes; + bool hasMipmaps; + bool hasFaces; + bool hasReferences; + }; + State state; + + struct DrvState { + void * mallocPtr; + } drvState; + + }; + Hal mHal; + + static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages, + RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE); virtual ~Allocation(); + void updateCache(); - void setCpuWritable(bool); - void setGpuWritable(bool); - void setCpuReadable(bool); - void setGpuReadable(bool); - - bool fixAllocation(); - - void * getPtr() const {return mPtr;} - const Type * getType() const {return mType.get();} + void * getPtr() const {return mHal.drvState.mallocPtr;} + const Type * getType() const {return mHal.state.type.get();} void syncAll(Context *rsc, RsAllocationUsageType src); - void deferedUploadToTexture(const Context *rsc); - void uploadToTexture(const Context *rsc); - uint32_t getTextureID() const {return mTextureID;} - - uint32_t getGLTarget() const; - - void deferedUploadToBufferObject(const Context *rsc); - void uploadToBufferObject(const Context *rsc); - uint32_t getBufferObjectID() const {return mBufferID;} - void copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len); void resize1D(Context *rsc, uint32_t dimX); @@ -74,9 +85,6 @@ public: void read(void *data); - void enableGLVertexBuffers() const; - void setupGLIndexBuffers() const; - void addProgramToDirty(const Program *); void removeProgramToDirty(const Program *); @@ -85,74 +93,33 @@ public: virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ALLOCATION; } static Allocation *createFromStream(Context *rsc, IStream *stream); - virtual void uploadCheck(Context *rsc); - bool getIsScript() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) != 0; } bool getIsTexture() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) != 0; + } + bool getIsRenderTarget() const { + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) != 0; } bool getIsBufferObject() const { - return (mUsageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0; + return (mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) != 0; } void incRefs(const void *ptr, size_t ct, size_t startOff = 0) const; void decRefs(const void *ptr, size_t ct, size_t startOff = 0) const; - void sendDirty() const; + void sendDirty(const Context *rsc) const; bool getHasGraphicsMipmaps() const { - return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE; + return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE; } protected: - ObjectBaseRef<const Type> mType; - void * mPtr; - Vector<const Program *> mToDirtyList; - // Is we have a non-null user bitmap callback we do not own the bits and - // instead call this function to free the memort when its time. - RsBitmapCallback_t mUserBitmapCallback; - void *mUserBitmapCallbackData; - - // Usage restrictions - bool mCpuWrite; - bool mCpuRead; - bool mGpuWrite; - bool mGpuRead; - - uint32_t mUsageFlags; - RsAllocationMipmapControl mMipmapControl; - - // more usage hint data from the application - // which can be used by a driver to pick the best memory type. - // Likely ignored for now - float mReadWriteRatio; - float mUpdateSize; - - - // Is this a legal structure to be used as a texture source. - // Initially this will require 1D or 2D and color data - uint32_t mTextureID; - - // Is this a legal structure to be used as a vertex source. - // Initially this will require 1D and x(yzw). Additional per element data - // is allowed. - uint32_t mBufferID; - - bool mUploadDefered; - private: - void init(Context *rsc, const Type *); - void upload2DTexture(bool isFirstUpload); - void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff, - uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h); - - void allocScriptMemory(); - void freeScriptMemory(); - + Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc); }; } diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 4c4987a..e65febb 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -16,10 +16,6 @@ #include "rsComponent.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#endif - using namespace android; using namespace android::renderscript; @@ -180,39 +176,6 @@ bool Component::isReference() const { return (mType >= RS_TYPE_ELEMENT); } -uint32_t Component::getGLType() const { -#ifndef ANDROID_RS_SERIALIZE - switch (mType) { - case RS_TYPE_UNSIGNED_5_6_5: return GL_UNSIGNED_SHORT_5_6_5; - case RS_TYPE_UNSIGNED_5_5_5_1: return GL_UNSIGNED_SHORT_5_5_5_1; - case RS_TYPE_UNSIGNED_4_4_4_4: return GL_UNSIGNED_SHORT_4_4_4_4; - - //case RS_TYPE_FLOAT_16: return GL_HALF_FLOAT; - case RS_TYPE_FLOAT_32: return GL_FLOAT; - case RS_TYPE_UNSIGNED_8: return GL_UNSIGNED_BYTE; - case RS_TYPE_UNSIGNED_16: return GL_UNSIGNED_SHORT; - case RS_TYPE_SIGNED_8: return GL_BYTE; - case RS_TYPE_SIGNED_16: return GL_SHORT; - default: break; - } -#endif //ANDROID_RS_SERIALIZE - return 0; -} - -uint32_t Component::getGLFormat() const { -#ifndef ANDROID_RS_SERIALIZE - switch (mKind) { - case RS_KIND_PIXEL_L: return GL_LUMINANCE; - case RS_KIND_PIXEL_A: return GL_ALPHA; - case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA; - case RS_KIND_PIXEL_RGB: return GL_RGB; - case RS_KIND_PIXEL_RGBA: return GL_RGBA; - default: break; - } -#endif //ANDROID_RS_SERIALIZE - return 0; -} - String8 Component::getGLSLType() const { if (mType == RS_TYPE_SIGNED_32) { switch (mVectorSize) { @@ -242,6 +205,7 @@ String8 Component::getGLSLType() const { return String8(); } + static const char * gTypeBasicStrings[] = { "NONE", "F16", diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h index 1bb4ff4..a448f0e 100644 --- a/libs/rs/rsComponent.h +++ b/libs/rs/rsComponent.h @@ -32,8 +32,6 @@ public: void set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize=1); - uint32_t getGLType() const; - uint32_t getGLFormat() const; String8 getGLSLType() const; void dumpLOGV(const char *prefix) const; diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index c63d183..44e9d89 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -18,9 +18,6 @@ #include "rsContext.h" #include "rsThreadIO.h" #include <ui/FramebufferNativeWindow.h> -#include <ui/PixelFormat.h> -#include <ui/EGLUtils.h> -#include <ui/egl/android_natives.h> #include <sys/types.h> #include <sys/resource.h> @@ -28,11 +25,6 @@ #include <cutils/properties.h> -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - #include <cutils/sched_policy.h> #include <sys/syscall.h> #include <string.h> @@ -40,232 +32,26 @@ using namespace android; using namespace android::renderscript; -pthread_key_t Context::gThreadTLSKey = 0; -uint32_t Context::gThreadTLSKeyCount = 0; -uint32_t Context::gGLContextCount = 0; pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER; -static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { - if (returnVal != EGL_TRUE) { - fprintf(stderr, "%s() returned %d\n", op, returnVal); - } - - for (EGLint error = eglGetError(); error != EGL_SUCCESS; error - = eglGetError()) { - fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), - error); - } -} - -void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { - -#define X(VAL) {VAL, #VAL} - struct {EGLint attribute; const char* name;} names[] = { - X(EGL_BUFFER_SIZE), - X(EGL_ALPHA_SIZE), - X(EGL_BLUE_SIZE), - X(EGL_GREEN_SIZE), - X(EGL_RED_SIZE), - X(EGL_DEPTH_SIZE), - X(EGL_STENCIL_SIZE), - X(EGL_CONFIG_CAVEAT), - X(EGL_CONFIG_ID), - X(EGL_LEVEL), - X(EGL_MAX_PBUFFER_HEIGHT), - X(EGL_MAX_PBUFFER_PIXELS), - X(EGL_MAX_PBUFFER_WIDTH), - X(EGL_NATIVE_RENDERABLE), - X(EGL_NATIVE_VISUAL_ID), - X(EGL_NATIVE_VISUAL_TYPE), - X(EGL_SAMPLES), - X(EGL_SAMPLE_BUFFERS), - X(EGL_SURFACE_TYPE), - X(EGL_TRANSPARENT_TYPE), - X(EGL_TRANSPARENT_RED_VALUE), - X(EGL_TRANSPARENT_GREEN_VALUE), - X(EGL_TRANSPARENT_BLUE_VALUE), - X(EGL_BIND_TO_TEXTURE_RGB), - X(EGL_BIND_TO_TEXTURE_RGBA), - X(EGL_MIN_SWAP_INTERVAL), - X(EGL_MAX_SWAP_INTERVAL), - X(EGL_LUMINANCE_SIZE), - X(EGL_ALPHA_MASK_SIZE), - X(EGL_COLOR_BUFFER_TYPE), - X(EGL_RENDERABLE_TYPE), - X(EGL_CONFORMANT), - }; -#undef X - - for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { - EGLint value = -1; - EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); - EGLint error = eglGetError(); - if (returnVal && error == EGL_SUCCESS) { - LOGV(" %s: %d (0x%x)", names[j].name, value, value); - } - } -} - - bool Context::initGLThread() { pthread_mutex_lock(&gInitMutex); LOGV("initGLThread start %p", this); - mEGL.mNumConfigs = -1; - EGLint configAttribs[128]; - EGLint *configAttribsPtr = configAttribs; - EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - - memset(configAttribs, 0, sizeof(configAttribs)); - - configAttribsPtr[0] = EGL_SURFACE_TYPE; - configAttribsPtr[1] = EGL_WINDOW_BIT; - configAttribsPtr += 2; - - configAttribsPtr[0] = EGL_RENDERABLE_TYPE; - configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; - configAttribsPtr += 2; - - if (mUserSurfaceConfig.depthMin > 0) { - configAttribsPtr[0] = EGL_DEPTH_SIZE; - configAttribsPtr[1] = mUserSurfaceConfig.depthMin; - configAttribsPtr += 2; - } - - if (mDev->mForceSW) { - configAttribsPtr[0] = EGL_CONFIG_CAVEAT; - configAttribsPtr[1] = EGL_SLOW_CONFIG; - configAttribsPtr += 2; - } - - configAttribsPtr[0] = EGL_NONE; - rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); - - LOGV("%p initEGL start", this); - mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - checkEglError("eglGetDisplay"); - - eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion); - checkEglError("eglInitialize"); - -#if 1 - PixelFormat pf = PIXEL_FORMAT_RGBA_8888; - if (mUserSurfaceConfig.alphaMin == 0) { - pf = PIXEL_FORMAT_RGBX_8888; - } - - status_t err = EGLUtils::selectConfigForPixelFormat(mEGL.mDisplay, configAttribs, pf, &mEGL.mConfig); - if (err) { - LOGE("%p, couldn't find an EGLConfig matching the screen format\n", this); - } - if (props.mLogVisual) { - printEGLConfiguration(mEGL.mDisplay, mEGL.mConfig); - } -#else - eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs); -#endif - - mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, context_attribs2); - checkEglError("eglCreateContext"); - if (mEGL.mContext == EGL_NO_CONTEXT) { - pthread_mutex_unlock(&gInitMutex); - LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", this); - return false; - } - gGLContextCount++; - - - EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; - mEGL.mSurfaceDefault = eglCreatePbufferSurface(mEGL.mDisplay, mEGL.mConfig, pbuffer_attribs); - checkEglError("eglCreatePbufferSurface"); - if (mEGL.mSurfaceDefault == EGL_NO_SURFACE) { - LOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE"); - pthread_mutex_unlock(&gInitMutex); - deinitEGL(); - return false; - } - - EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext); - if (ret == EGL_FALSE) { - LOGE("eglMakeCurrent returned EGL_FALSE"); - checkEglError("eglMakeCurrent", ret); - pthread_mutex_unlock(&gInitMutex); - deinitEGL(); - return false; - } - - mGL.mVersion = glGetString(GL_VERSION); - mGL.mVendor = glGetString(GL_VENDOR); - mGL.mRenderer = glGetString(GL_RENDERER); - mGL.mExtensions = glGetString(GL_EXTENSIONS); - - //LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); - //LOGV("GL Version %s", mGL.mVersion); - //LOGV("GL Vendor %s", mGL.mVendor); - //LOGV("GL Renderer %s", mGL.mRenderer); - //LOGV("GL Extensions %s", mGL.mExtensions); - - const char *verptr = NULL; - if (strlen((const char *)mGL.mVersion) > 9) { - if (!memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) { - verptr = (const char *)mGL.mVersion + 12; - } - if (!memcmp(mGL.mVersion, "OpenGL ES ", 10)) { - verptr = (const char *)mGL.mVersion + 9; - } - } - - if (!verptr) { - LOGE("Error, OpenGL ES Lite not supported"); + if (!mHal.funcs.initGraphics(this)) { pthread_mutex_unlock(&gInitMutex); - deinitEGL(); + LOGE("%p, initGraphics failed", this); return false; - } else { - sscanf(verptr, " %i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion); } - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &mGL.mMaxVertexAttribs); - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &mGL.mMaxVertexUniformVectors); - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGL.mMaxVertexTextureUnits); - - glGetIntegerv(GL_MAX_VARYING_VECTORS, &mGL.mMaxVaryingVectors); - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGL.mMaxTextureImageUnits); - - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mGL.mMaxFragmentTextureImageUnits); - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGL.mMaxFragmentUniformVectors); - - mGL.OES_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_OES_texture_npot"); - mGL.GL_IMG_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_IMG_texture_npot"); - mGL.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)mGL.mExtensions, "GL_NV_texture_npot_2D_mipmap"); - mGL.EXT_texture_max_aniso = 1.0f; - bool hasAniso = NULL != strstr((const char *)mGL.mExtensions, "GL_EXT_texture_filter_anisotropic"); - if (hasAniso) { - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mGL.EXT_texture_max_aniso); - } - - LOGV("initGLThread end %p", this); pthread_mutex_unlock(&gInitMutex); return true; } void Context::deinitEGL() { LOGV("%p, deinitEGL", this); - - if (mEGL.mContext != EGL_NO_CONTEXT) { - eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(mEGL.mDisplay, mEGL.mSurfaceDefault); - if (mEGL.mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mEGL.mDisplay, mEGL.mSurface); - } - eglDestroyContext(mEGL.mDisplay, mEGL.mContext); - checkEglError("eglDestroyContext"); - } - - gGLContextCount--; - if (!gGLContextCount) { - eglTerminate(mEGL.mDisplay); - } + mHal.funcs.shutdownGraphics(this); } Context::PushState::PushState(Context *con) { @@ -297,45 +83,22 @@ uint32_t Context::runScript(Script *s) { return ret; } -void Context::checkError(const char *msg, bool isFatal) const { - - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - char buf[1024]; - snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg); - - if (isFatal) { - setError(RS_ERROR_FATAL_DRIVER, buf); - } else { - switch (err) { - case GL_OUT_OF_MEMORY: - setError(RS_ERROR_OUT_OF_MEMORY, buf); - break; - default: - setError(RS_ERROR_DRIVER, buf); - break; - } - } - - LOGE("%p, %s", this, buf); - } -} - uint32_t Context::runRootScript() { - glViewport(0, 0, mWidth, mHeight); - timerSet(RS_TIMER_SCRIPT); mStateFragmentStore.mLast.clear(); uint32_t ret = runScript(mRootScript.get()); - checkError("runRootScript"); return ret; } uint64_t Context::getTime() const { +#ifndef ANDROID_RS_SERIALIZE struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000); +#else + return 0; +#endif //ANDROID_RS_SERIALIZE } void Context::timerReset() { @@ -400,20 +163,17 @@ void Context::timerPrint() { } bool Context::setupCheck() { - if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) { - LOGE("Context::setupCheck() 1 fail"); - return false; - } - mFragmentStore->setupGL2(this, &mStateFragmentStore); - mFragment->setupGL2(this, &mStateFragment, &mShaderCache); - mRaster->setupGL2(this, &mStateRaster); - mVertex->setupGL2(this, &mStateVertex, &mShaderCache); + mFragmentStore->setup(this, &mStateFragmentStore); + mFragment->setup(this, &mStateFragment); + mRaster->setup(this, &mStateRaster); + mVertex->setup(this, &mStateVertex); + mFBOCache.setup(this); return true; } void Context::setupProgramStore() { - mFragmentStore->setupGL2(this, &mStateFragmentStore); + mFragmentStore->setup(this, &mStateFragmentStore); } static bool getProp(const char *str) { @@ -429,6 +189,8 @@ void Context::displayDebugStats() { mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA); uint32_t bufferLen = strlen(buffer); + ObjectBaseRef<Font> lastFont(getFont()); + setFont(NULL); float shadowCol = 0.1f; mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f); mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 6); @@ -436,98 +198,92 @@ void Context::displayDebugStats() { mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f); mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 7); + setFont(lastFont.get()); mStateFont.setFontColor(oldR, oldG, oldB, oldA); } void * Context::threadProc(void *vrsc) { - Context *rsc = static_cast<Context *>(vrsc); - rsc->mNativeThreadId = gettid(); - - setpriority(PRIO_PROCESS, rsc->mNativeThreadId, ANDROID_PRIORITY_DISPLAY); - rsc->mThreadPriority = ANDROID_PRIORITY_DISPLAY; - - rsc->props.mLogTimes = getProp("debug.rs.profile"); - rsc->props.mLogScripts = getProp("debug.rs.script"); - rsc->props.mLogObjects = getProp("debug.rs.object"); - rsc->props.mLogShaders = getProp("debug.rs.shader"); - rsc->props.mLogShadersAttr = getProp("debug.rs.shader.attributes"); - rsc->props.mLogShadersUniforms = getProp("debug.rs.shader.uniforms"); - rsc->props.mLogVisual = getProp("debug.rs.visual"); - - rsc->mTlsStruct = new ScriptTLSStruct; - if (!rsc->mTlsStruct) { - LOGE("Error allocating tls storage"); - rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed allocation for TLS"); - return NULL; - } - rsc->mTlsStruct->mContext = rsc; - rsc->mTlsStruct->mScript = NULL; - int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct); - if (status) { - LOGE("pthread_setspecific %i", status); - } - - if (!rsc->initGLThread()) { - rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL"); - return NULL; - } - - if (rsc->mIsGraphicsContext) { - rsc->mStateRaster.init(rsc); - rsc->setProgramRaster(NULL); - rsc->mStateVertex.init(rsc); - rsc->setProgramVertex(NULL); - rsc->mStateFragment.init(rsc); - rsc->setProgramFragment(NULL); - rsc->mStateFragmentStore.init(rsc); - rsc->setProgramStore(NULL); - rsc->mStateFont.init(rsc); - rsc->setFont(NULL); - rsc->mStateVertexArray.init(rsc); - } - - rsc->mRunning = true; - bool mDraw = true; - while (!rsc->mExit) { - mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw); - mDraw &= (rsc->mRootScript.get() != NULL); - mDraw &= (rsc->mWndSurface != NULL); - - uint32_t targetTime = 0; - if (mDraw && rsc->mIsGraphicsContext) { - targetTime = rsc->runRootScript(); - - if (rsc->props.mLogVisual) { - rsc->displayDebugStats(); - } - - mDraw = targetTime && !rsc->mPaused; - rsc->timerSet(RS_TIMER_CLEAR_SWAP); - eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); - rsc->timerFrame(); - rsc->timerSet(RS_TIMER_INTERNAL); - rsc->timerPrint(); - rsc->timerReset(); - } - if (targetTime > 1) { - int32_t t = (targetTime - (int32_t)(rsc->mTimeMSLastScript + rsc->mTimeMSLastSwap)) * 1000; - if (t > 0) { - usleep(t); - } - } - } - - LOGV("%p, RS Thread exiting", rsc); - - if (rsc->mIsGraphicsContext) { - pthread_mutex_lock(&gInitMutex); - rsc->deinitEGL(); - pthread_mutex_unlock(&gInitMutex); - } - delete rsc->mTlsStruct; - - LOGV("%p, RS Thread exited", rsc); - return NULL; + Context *rsc = static_cast<Context *>(vrsc); +#ifndef ANDROID_RS_SERIALIZE + rsc->mNativeThreadId = gettid(); + setpriority(PRIO_PROCESS, rsc->mNativeThreadId, ANDROID_PRIORITY_DISPLAY); + rsc->mThreadPriority = ANDROID_PRIORITY_DISPLAY; +#endif //ANDROID_RS_SERIALIZE + rsc->props.mLogTimes = getProp("debug.rs.profile"); + rsc->props.mLogScripts = getProp("debug.rs.script"); + rsc->props.mLogObjects = getProp("debug.rs.object"); + rsc->props.mLogShaders = getProp("debug.rs.shader"); + rsc->props.mLogShadersAttr = getProp("debug.rs.shader.attributes"); + rsc->props.mLogShadersUniforms = getProp("debug.rs.shader.uniforms"); + rsc->props.mLogVisual = getProp("debug.rs.visual"); + + if (!rsdHalInit(rsc, 0, 0)) { + rsc->setError(RS_ERROR_FATAL_DRIVER, "Failed initializing GL"); + LOGE("Hal init failed"); + return NULL; + } + rsc->mHal.funcs.setPriority(rsc, rsc->mThreadPriority); + + if (rsc->mIsGraphicsContext) { + if (!rsc->initGLThread()) { + rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL"); + return NULL; + } + + rsc->mStateRaster.init(rsc); + rsc->setProgramRaster(NULL); + rsc->mStateVertex.init(rsc); + rsc->setProgramVertex(NULL); + rsc->mStateFragment.init(rsc); + rsc->setProgramFragment(NULL); + rsc->mStateFragmentStore.init(rsc); + rsc->setProgramStore(NULL); + rsc->mStateFont.init(rsc); + rsc->setFont(NULL); + rsc->mFBOCache.init(rsc); + } + + rsc->mRunning = true; + bool mDraw = true; + while (!rsc->mExit) { + mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw); + mDraw &= (rsc->mRootScript.get() != NULL); + mDraw &= rsc->mHasSurface; + + uint32_t targetTime = 0; + if (mDraw && rsc->mIsGraphicsContext) { + targetTime = rsc->runRootScript(); + + if (rsc->props.mLogVisual) { + rsc->displayDebugStats(); + } + + mDraw = targetTime && !rsc->mPaused; + rsc->timerSet(RS_TIMER_CLEAR_SWAP); + rsc->mHal.funcs.swap(rsc); + rsc->timerFrame(); + rsc->timerSet(RS_TIMER_INTERNAL); + rsc->timerPrint(); + rsc->timerReset(); + } + if (targetTime > 1) { + int32_t t = (targetTime - (int32_t)(rsc->mTimeMSLastScript + rsc->mTimeMSLastSwap)) * 1000; + if (t > 0) { + usleep(t); + } + } + } + + LOGV("%p, RS Thread exiting", rsc); + + if (rsc->mIsGraphicsContext) { + pthread_mutex_lock(&gInitMutex); + rsc->deinitEGL(); + pthread_mutex_unlock(&gInitMutex); + } + + LOGV("%p, RS Thread exited", rsc); + return NULL; } void Context::destroyWorkerThreadResources() { @@ -545,62 +301,12 @@ void Context::destroyWorkerThreadResources() { mStateFragment.deinit(this); mStateFragmentStore.deinit(this); mStateFont.deinit(this); - mShaderCache.cleanupAll(); + mFBOCache.deinit(this); } //LOGV("destroyWorkerThreadResources 2"); mExit = true; } -void * Context::helperThreadProc(void *vrsc) { - Context *rsc = static_cast<Context *>(vrsc); - uint32_t idx = (uint32_t)android_atomic_inc(&rsc->mWorkers.mLaunchCount); - - //LOGV("RS helperThread starting %p idx=%i", rsc, idx); - - rsc->mWorkers.mLaunchSignals[idx].init(); - rsc->mWorkers.mNativeThreadId[idx] = gettid(); - -#if 0 - typedef struct {uint64_t bits[1024 / 64]; } cpu_set_t; - cpu_set_t cpuset; - memset(&cpuset, 0, sizeof(cpuset)); - cpuset.bits[idx / 64] |= 1ULL << (idx % 64); - int ret = syscall(241, rsc->mWorkers.mNativeThreadId[idx], - sizeof(cpuset), &cpuset); - LOGE("SETAFFINITY ret = %i %s", ret, EGLUtils::strerror(ret)); -#endif - - setpriority(PRIO_PROCESS, rsc->mWorkers.mNativeThreadId[idx], rsc->mThreadPriority); - int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct); - if (status) { - LOGE("pthread_setspecific %i", status); - } - - while (!rsc->mExit) { - rsc->mWorkers.mLaunchSignals[idx].wait(); - if (rsc->mWorkers.mLaunchCallback) { - rsc->mWorkers.mLaunchCallback(rsc->mWorkers.mLaunchData, idx); - } - android_atomic_dec(&rsc->mWorkers.mRunningCount); - rsc->mWorkers.mCompleteSignal.set(); - } - - //LOGV("RS helperThread exited %p idx=%i", rsc, idx); - return NULL; -} - -void Context::launchThreads(WorkerCallback_t cbk, void *data) { - mWorkers.mLaunchData = data; - mWorkers.mLaunchCallback = cbk; - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - mWorkers.mLaunchSignals[ct].set(); - } - while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { - mWorkers.mCompleteSignal.wait(); - } -} - void Context::setPriority(int32_t p) { // Note: If we put this in the proper "background" policy // the wallpapers can become completly unresponsive at times. @@ -617,9 +323,6 @@ void Context::setPriority(int32_t p) { } #else setpriority(PRIO_PROCESS, mNativeThreadId, p); - for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { - setpriority(PRIO_PROCESS, mWorkers.mNativeThreadId[ct], p); - } #endif } @@ -631,10 +334,16 @@ Context::Context() { mObjHead = NULL; mError = RS_ERROR_NONE; mDPI = 96; + mIsContextLite = false; } Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) { Context * rsc = new Context(); + + // Temporary to avoid breaking the tools + if (!dev) { + return rsc; + } if (!rsc->initContext(dev, sc)) { delete rsc; return NULL; @@ -642,9 +351,17 @@ Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) { return rsc; } +Context * Context::createContextLite() { + Context * rsc = new Context(); + rsc->mIsContextLite = true; + return rsc; +} + bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { pthread_mutex_lock(&gInitMutex); + mIO.init(); + dev->addContext(this); mDev = dev; if (sc) { @@ -653,23 +370,11 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { memset(&mUserSurfaceConfig, 0, sizeof(mUserSurfaceConfig)); } - memset(&mEGL, 0, sizeof(mEGL)); - memset(&mGL, 0, sizeof(mGL)); mIsGraphicsContext = sc != NULL; int status; pthread_attr_t threadAttr; - if (!gThreadTLSKeyCount) { - status = pthread_key_create(&gThreadTLSKey, NULL); - if (status) { - LOGE("Failed to init thread tls key."); - pthread_mutex_unlock(&gInitMutex); - return false; - } - } - gThreadTLSKeyCount++; - pthread_mutex_unlock(&gInitMutex); // Global init done at this point. @@ -680,20 +385,11 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { return false; } - mWndSurface = NULL; + mHasSurface = false; timerInit(); timerSet(RS_TIMER_INTERNAL); - int cpu = sysconf(_SC_NPROCESSORS_ONLN); - LOGV("RS Launching thread(s), reported CPU count %i", cpu); - if (cpu < 2) cpu = 0; - - mWorkers.mCount = (uint32_t)cpu; - mWorkers.mThreadId = (pthread_t *) calloc(mWorkers.mCount, sizeof(pthread_t)); - mWorkers.mNativeThreadId = (pid_t *) calloc(mWorkers.mCount, sizeof(pid_t)); - mWorkers.mLaunchSignals = new Signal[mWorkers.mCount]; - mWorkers.mLaunchCallback = NULL; status = pthread_create(&mThreadId, &threadAttr, threadProc, this); if (status) { LOGE("Failed to start rs context thread."); @@ -704,23 +400,10 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { } if (mError != RS_ERROR_NONE) { + LOGE("Errors during thread init"); return false; } - mWorkers.mCompleteSignal.init(); - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - android_atomic_release_store(0, &mWorkers.mLaunchCount); - for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { - status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this); - if (status) { - mWorkers.mCount = ct; - LOGE("Created fewer than expected number of RS threads."); - break; - } - } - while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { - usleep(100); - } pthread_attr_destroy(&threadAttr); return true; } @@ -728,73 +411,40 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { Context::~Context() { LOGV("Context::~Context"); - mIO.mToCore.flush(); - rsAssert(mExit); - mExit = true; - mPaused = false; - void *res; + if (!mIsContextLite) { + mIO.coreFlush(); + rsAssert(mExit); + mExit = true; + mPaused = false; + void *res; - mIO.shutdown(); - int status = pthread_join(mThreadId, &res); + mIO.shutdown(); + int status = pthread_join(mThreadId, &res); - // Cleanup compute threads. - mWorkers.mLaunchData = NULL; - mWorkers.mLaunchCallback = NULL; - android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - mWorkers.mLaunchSignals[ct].set(); - } - for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { - status = pthread_join(mWorkers.mThreadId[ct], &res); - } - rsAssert(android_atomic_acquire_load(&mWorkers.mRunningCount) == 0); + if (mHal.funcs.shutdownDriver) { + mHal.funcs.shutdownDriver(this); + } - // Global structure cleanup. - pthread_mutex_lock(&gInitMutex); - if (mDev) { - mDev->removeContext(this); - --gThreadTLSKeyCount; - if (!gThreadTLSKeyCount) { - pthread_key_delete(gThreadTLSKey); + // Global structure cleanup. + pthread_mutex_lock(&gInitMutex); + if (mDev) { + mDev->removeContext(this); + mDev = NULL; } - mDev = NULL; + pthread_mutex_unlock(&gInitMutex); } - pthread_mutex_unlock(&gInitMutex); LOGV("Context::~Context done"); } -void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) { +void Context::setSurface(uint32_t w, uint32_t h, RsNativeWindow sur) { rsAssert(mIsGraphicsContext); + mHal.funcs.setSurface(this, w, h, sur); - EGLBoolean ret; - // WAR: Some drivers fail to handle 0 size surfaces correcntly. - // Use the pbuffer to avoid this pitfall. - if ((mEGL.mSurface != NULL) || (w == 0) || (h == 0)) { - ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext); - checkEglError("eglMakeCurrent", ret); - - ret = eglDestroySurface(mEGL.mDisplay, mEGL.mSurface); - checkEglError("eglDestroySurface", ret); - - mEGL.mSurface = NULL; - mWidth = 1; - mHeight = 1; - } - - mWndSurface = sur; - if (mWndSurface != NULL) { - mWidth = w; - mHeight = h; - - mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL); - checkEglError("eglCreateWindowSurface"); - if (mEGL.mSurface == EGL_NO_SURFACE) { - LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); - } - - ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); - checkEglError("eglMakeCurrent", ret); + mHasSurface = sur != NULL; + mWidth = w; + mHeight = h; + if (mWidth && mHeight) { mStateVertex.updateSize(this); } } @@ -874,69 +524,18 @@ void Context::removeName(ObjectBase *obj) { } } -RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID, bool wait) { - *receiveLen = 0; - if (!wait && mIO.mToClient.isEmpty()) { - return RS_MESSAGE_TO_CLIENT_NONE; - } - - uint32_t bytesData = 0; - uint32_t commandID = 0; - const uint32_t *d = (const uint32_t *)mIO.mToClient.get(&commandID, &bytesData); - *receiveLen = bytesData - sizeof(uint32_t); - if (bytesData) { - *subID = d[0]; - } - return (RsMessageToClientType)commandID; +RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID) { + return (RsMessageToClientType)mIO.getClientHeader(receiveLen, subID); } -RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait) { - //LOGE("getMessageToClient %i %i", bufferLen, wait); - *receiveLen = 0; - if (!wait && mIO.mToClient.isEmpty()) { - return RS_MESSAGE_TO_CLIENT_NONE; - } - - //LOGE("getMessageToClient 2 con=%p", this); - uint32_t bytesData = 0; - uint32_t commandID = 0; - const uint32_t *d = (const uint32_t *)mIO.mToClient.get(&commandID, &bytesData); - //LOGE("getMessageToClient 3 %i %i", commandID, bytesData); - - *receiveLen = bytesData - sizeof(uint32_t); - *subID = d[0]; - - //LOGE("getMessageToClient %i %i", commandID, *subID); - if (bufferLen >= bytesData) { - memcpy(data, d+1, *receiveLen); - mIO.mToClient.next(); - return (RsMessageToClientType)commandID; - } - return RS_MESSAGE_TO_CLIENT_RESIZE; +RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen) { + return (RsMessageToClientType)mIO.getClientPayload(data, receiveLen, subID, bufferLen); } bool Context::sendMessageToClient(const void *data, RsMessageToClientType cmdID, uint32_t subID, size_t len, bool waitForSpace) const { - //LOGE("sendMessageToClient %i %i %i %i", cmdID, subID, len, waitForSpace); - if (cmdID == 0) { - LOGE("Attempting to send invalid command 0 to client."); - return false; - } - if (!waitForSpace) { - if (!mIO.mToClient.makeSpaceNonBlocking(len + 12)) { - // Not enough room, and not waiting. - return false; - } - } - //LOGE("sendMessageToClient 2"); - uint32_t *p = (uint32_t *)mIO.mToClient.reserve(len + sizeof(subID)); - p[0] = subID; - if (len > 0) { - memcpy(p+1, data, len); - } - mIO.mToClient.commit(cmdID, len + sizeof(subID)); - //LOGE("sendMessageToClient 3"); - return true; + + return mIO.sendToClient(cmdID, subID, data, len, waitForSpace); } void Context::initToClient() { @@ -946,7 +545,7 @@ void Context::initToClient() { } void Context::deinitToClient() { - mIO.mToClient.shutdown(); + mIO.clientShutdown(); } void Context::setError(RsError e, const char *msg) const { @@ -959,21 +558,9 @@ void Context::dumpDebug() const { LOGE("RS Context debug %p", this); LOGE("RS Context debug"); - LOGE(" EGL ver %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); - LOGE(" EGL context %p surface %p, Display=%p", mEGL.mContext, mEGL.mSurface, mEGL.mDisplay); - LOGE(" GL vendor: %s", mGL.mVendor); - LOGE(" GL renderer: %s", mGL.mRenderer); - LOGE(" GL Version: %s", mGL.mVersion); - LOGE(" GL Extensions: %s", mGL.mExtensions); - LOGE(" GL int Versions %i %i", mGL.mMajorVersion, mGL.mMinorVersion); LOGE(" RS width %i, height %i", mWidth, mHeight); LOGE(" RS running %i, exit %i, paused %i", mRunning, mExit, mPaused); - LOGE(" RS pThreadID %li, nativeThreadID %i", mThreadId, mNativeThreadId); - - LOGV("MAX Textures %i, %i %i", mGL.mMaxVertexTextureUnits, mGL.mMaxFragmentTextureImageUnits, mGL.mMaxTextureImageUnits); - LOGV("MAX Attribs %i", mGL.mMaxVertexAttribs); - LOGV("MAX Uniforms %i, %i", mGL.mMaxVertexUniformVectors, mGL.mMaxFragmentUniformVectors); - LOGV("MAX Varyings %i", mGL.mMaxVaryingVectors); + LOGE(" RS pThreadID %li, nativeThreadID %i", (long int)mThreadId, mNativeThreadId); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1026,9 +613,9 @@ void rsi_ContextBindFont(Context *rsc, RsFont vfont) { rsc->setFont(font); } -void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len) { +void rsi_AssignName(Context *rsc, RsObjectBase obj, const char *name, size_t name_length) { ObjectBase *ob = static_cast<ObjectBase *>(obj); - rsc->assignName(ob, name, len); + rsc->assignName(ob, name, name_length); } void rsi_ObjDestroy(Context *rsc, void *optr) { @@ -1045,7 +632,7 @@ void rsi_ContextResume(Context *rsc) { rsc->resume(); } -void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur) { +void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) { rsc->setSurface(w, h, sur); } @@ -1058,18 +645,40 @@ void rsi_ContextDump(Context *rsc, int32_t bits) { } void rsi_ContextDestroyWorker(Context *rsc) { - rsc->destroyWorkerThreadResources();; + rsc->destroyWorkerThreadResources(); } +void rsi_ContextDestroy(Context *rsc) { + LOGV("rsContextDestroy %p", rsc); + rsContextDestroyWorker(rsc); + delete rsc; + LOGV("rsContextDestroy 2 %p", rsc); } + + +RsMessageToClientType rsi_ContextPeekMessage(Context *rsc, + size_t * receiveLen, size_t receiveLen_length, + uint32_t * subID, size_t subID_length) { + return rsc->peekMessageToClient(receiveLen, subID); } -void rsContextDestroy(RsContext vcon) { - LOGV("rsContextDestroy %p", vcon); - Context *rsc = static_cast<Context *>(vcon); - rsContextDestroyWorker(rsc); - delete rsc; - LOGV("rsContextDestroy 2 %p", vcon); +RsMessageToClientType rsi_ContextGetMessage(Context *rsc, void * data, size_t data_length, + size_t * receiveLen, size_t receiveLen_length, + uint32_t * subID, size_t subID_length) { + rsAssert(subID_length == sizeof(uint32_t)); + rsAssert(receiveLen_length == sizeof(size_t)); + return rsc->getMessageToClient(data, receiveLen, subID, data_length); +} + +void rsi_ContextInitToClient(Context *rsc) { + rsc->initToClient(); +} + +void rsi_ContextDeinitToClient(Context *rsc) { + rsc->deinitToClient(); +} + +} } RsContext rsContextCreate(RsDevice vdev, uint32_t version) { @@ -1089,26 +698,6 @@ RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, return rsc; } -RsMessageToClientType rsContextPeekMessage(RsContext vrsc, size_t *receiveLen, uint32_t *subID, bool wait) { - Context * rsc = static_cast<Context *>(vrsc); - return rsc->peekMessageToClient(receiveLen, subID, wait); -} - -RsMessageToClientType rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait) { - Context * rsc = static_cast<Context *>(vrsc); - return rsc->getMessageToClient(data, receiveLen, subID, bufferLen, wait); -} - -void rsContextInitToClient(RsContext vrsc) { - Context * rsc = static_cast<Context *>(vrsc); - rsc->initToClient(); -} - -void rsContextDeinitToClient(RsContext vrsc) { - Context * rsc = static_cast<Context *>(vrsc); - rsc->deinitToClient(); -} - // Only to be called at a3d load time, before object is visible to user // not thread safe void rsaGetName(RsContext con, void * obj, const char **name) { diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 50f63df..309fe95 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -22,10 +22,11 @@ #include "rsAllocation.h" #include "rsMesh.h" -#ifndef ANDROID_RS_SERIALIZE +#include "rs_hal.h" + #include "rsMutex.h" #include "rsThreadIO.h" -#include "rsMatrix.h" +#include "rsMatrix4x4.h" #include "rsDevice.h" #include "rsScriptC.h" #include "rsAdapter.h" @@ -35,15 +36,11 @@ #include "rsProgramStore.h" #include "rsProgramRaster.h" #include "rsProgramVertex.h" -#include "rsShaderCache.h" -#include "rsVertexArray.h" +#include "rsFBOCache.h" #include "rsgApiStructs.h" #include "rsLocklessFifo.h" -#include <ui/egl/android_natives.h> -#endif // ANDROID_RS_SERIALIZE - // --------------------------------------------------------------------------- namespace android { @@ -67,25 +64,23 @@ namespace renderscript { #define CHECK_OBJ_OR_NULL(o) #endif -#ifndef ANDROID_RS_SERIALIZE - class Context { public: + struct Hal { + void * drv; + + RsdHalFunctions funcs; + }; + Hal mHal; + static Context * createContext(Device *, const RsSurfaceConfig *sc); + static Context * createContextLite(); ~Context(); - static pthread_key_t gThreadTLSKey; - static uint32_t gThreadTLSKeyCount; - static uint32_t gGLContextCount; static pthread_mutex_t gInitMutex; // Library mutex (for providing thread-safe calls from the runtime) static pthread_mutex_t gLibMutex; - struct ScriptTLSStruct { - Context * mContext; - Script * mScript; - }; - class PushState { public: PushState(Context *); @@ -100,12 +95,8 @@ public: Context *mRsc; }; - ScriptTLSStruct *mTlsStruct; RsSurfaceConfig mUserSurfaceConfig; - typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); - - //StructuredAllocationContext mStateAllocation; ElementState mStateElement; TypeState mStateType; SamplerState mStateSampler; @@ -113,11 +104,10 @@ public: ProgramStoreState mStateFragmentStore; ProgramRasterState mStateRaster; ProgramVertexState mStateVertex; - VertexArrayState mStateVertexArray; FontState mStateFont; ScriptCState mScriptC; - ShaderCache mShaderCache; + FBOCache mFBOCache; void swapBuffers(); void setRootScript(Script *); @@ -140,15 +130,15 @@ public: void pause(); void resume(); - void setSurface(uint32_t w, uint32_t h, ANativeWindow *sur); + void setSurface(uint32_t w, uint32_t h, RsNativeWindow sur); void setPriority(int32_t p); void destroyWorkerThreadResources(); void assignName(ObjectBase *obj, const char *name, uint32_t len); void removeName(ObjectBase *obj); - RsMessageToClientType peekMessageToClient(size_t *receiveLen, uint32_t *subID, bool wait); - RsMessageToClientType getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait); + RsMessageToClientType peekMessageToClient(size_t *receiveLen, uint32_t *subID); + RsMessageToClientType getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen); bool sendMessageToClient(const void *data, RsMessageToClientType cmdID, uint32_t subID, size_t len, bool waitForSpace) const; uint32_t runScript(Script *s); @@ -202,63 +192,15 @@ public: } props; void dumpDebug() const; - void checkError(const char *, bool isFatal = false) const; void setError(RsError e, const char *msg = NULL) const; mutable const ObjectBase * mObjHead; - bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;} - bool ext_GL_IMG_texture_npot() const {return mGL.GL_IMG_texture_npot;} - bool ext_GL_NV_texture_npot_2D_mipmap() const {return mGL.GL_NV_texture_npot_2D_mipmap;} - float ext_texture_max_aniso() const {return mGL.EXT_texture_max_aniso; } - uint32_t getMaxFragmentTextures() const {return mGL.mMaxFragmentTextureImageUnits;} - uint32_t getMaxFragmentUniformVectors() const {return mGL.mMaxFragmentUniformVectors;} - uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;} - uint32_t getMaxVertexAttributes() const {return mGL.mMaxVertexAttribs;} - - void launchThreads(WorkerCallback_t cbk, void *data); - uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mCount;} uint32_t getDPI() const {return mDPI;} void setDPI(uint32_t dpi) {mDPI = dpi;} -protected: Device *mDev; - - struct { - EGLint mNumConfigs; - EGLint mMajorVersion; - EGLint mMinorVersion; - EGLConfig mConfig; - EGLContext mContext; - EGLSurface mSurface; - EGLSurface mSurfaceDefault; - EGLDisplay mDisplay; - } mEGL; - - struct { - const uint8_t * mVendor; - const uint8_t * mRenderer; - const uint8_t * mVersion; - const uint8_t * mExtensions; - - uint32_t mMajorVersion; - uint32_t mMinorVersion; - - int32_t mMaxVaryingVectors; - int32_t mMaxTextureImageUnits; - - int32_t mMaxFragmentTextureImageUnits; - int32_t mMaxFragmentUniformVectors; - - int32_t mMaxVertexAttribs; - int32_t mMaxVertexUniformVectors; - int32_t mMaxVertexTextureUnits; - - bool OES_texture_npot; - bool GL_IMG_texture_npot; - bool GL_NV_texture_npot_2D_mipmap; - float EXT_texture_max_aniso; - } mGL; +protected: uint32_t mDPI; uint32_t mWidth; @@ -274,20 +216,6 @@ protected: pthread_t mThreadId; pid_t mNativeThreadId; - struct Workers { - volatile int mRunningCount; - volatile int mLaunchCount; - uint32_t mCount; - pthread_t *mThreadId; - pid_t *mNativeThreadId; - Signal mCompleteSignal; - - Signal *mLaunchSignals; - WorkerCallback_t mLaunchCallback; - void *mLaunchData; - }; - Workers mWorkers; - ObjectBaseRef<Script> mRootScript; ObjectBaseRef<ProgramFragment> mFragment; ObjectBaseRef<ProgramVertex> mVertex; @@ -310,7 +238,8 @@ private: static void * threadProc(void *); static void * helperThreadProc(void *); - ANativeWindow *mWndSurface; + bool mHasSurface; + bool mIsContextLite; Vector<ObjectBase *> mNames; @@ -327,39 +256,6 @@ private: uint32_t mAverageFPS; }; -#else - -class Context { -public: - Context() { - mObjHead = NULL; - } - ~Context() { - ObjectBase::zeroAllUserRef(this); - } - - ElementState mStateElement; - TypeState mStateType; - - struct { - bool mLogTimes; - bool mLogScripts; - bool mLogObjects; - bool mLogShaders; - bool mLogShadersAttr; - bool mLogShadersUniforms; - bool mLogVisual; - } props; - - void setError(RsError e, const char *msg = NULL) { } - - mutable const ObjectBase * mObjHead; - -protected: - -}; -#endif //ANDROID_RS_SERIALIZE - } // renderscript } // android #endif diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp index 477cb61..2b58e9e 100644 --- a/libs/rs/rsElement.cpp +++ b/libs/rs/rsElement.cpp @@ -347,13 +347,18 @@ RsElement rsi_ElementCreate(Context *rsc, return (RsElement)e; } + RsElement rsi_ElementCreate2(Context *rsc, - size_t count, const RsElement * ein, + size_t ein_length, + const char ** names, + size_t nameLengths_length, const size_t * nameLengths, - const uint32_t * arraySizes) { - const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes); + + const uint32_t * arraySizes, + size_t arraySizes_length) { + const Element *e = Element::create(rsc, ein_length, (const Element **)ein, names, nameLengths, arraySizes); e->incUserRef(); return (RsElement)e; } diff --git a/libs/rs/rsFBOCache.cpp b/libs/rs/rsFBOCache.cpp new file mode 100644 index 0000000..6960ef2 --- /dev/null +++ b/libs/rs/rsFBOCache.cpp @@ -0,0 +1,96 @@ +/* + * 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 "rsFBOCache.h" + +#include "rsContext.h" +#include "rsAllocation.h" + +using namespace android; +using namespace android::renderscript; + + +FBOCache::FBOCache() { + mDirty = true; + mHal.state.colorTargetsCount = 1; + mHal.state.colorTargets = new ObjectBaseRef<Allocation>[mHal.state.colorTargetsCount]; +} + +FBOCache::~FBOCache() { + delete[] mHal.state.colorTargets; +} + +void FBOCache::init(Context *rsc) { + rsc->mHal.funcs.framebuffer.init(rsc, this); +} + +void FBOCache::deinit(Context *rsc) { + rsc->mHal.funcs.framebuffer.destroy(rsc, this); +} + +void FBOCache::bindColorTarget(Context *rsc, Allocation *a, uint32_t slot) { + if (slot >= mHal.state.colorTargetsCount) { + LOGE("Invalid render target index"); + return; + } + if (a != NULL) { + if (!a->getIsTexture()) { + LOGE("Invalid Color Target"); + return; + } + } + mHal.state.colorTargets[slot].set(a); + mDirty = true; +} + +void FBOCache::bindDepthTarget(Context *rsc, Allocation *a) { + if (a != NULL) { + if (!a->getIsRenderTarget()) { + LOGE("Invalid Depth Target"); + return; + } + } + mHal.state.depthTarget.set(a); + mDirty = true; +} + +void FBOCache::resetAll(Context *) { + for (uint32_t i = 0; i < mHal.state.colorTargetsCount; i ++) { + mHal.state.colorTargets[i].set(NULL); + } + mHal.state.depthTarget.set(NULL); + mDirty = true; +} + +void FBOCache::setup(Context *rsc) { + if (!mDirty) { + return; + } + + if (mHal.state.depthTarget.get() != NULL) { + mHal.state.depthTarget->syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT); + } + + for (uint32_t i = 0; i < mHal.state.colorTargetsCount; i ++) { + if (mHal.state.colorTargets[i].get() != NULL) { + mHal.state.colorTargets[i]->syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT); + } + } + + rsc->mHal.funcs.framebuffer.setActive(rsc, this); + + mDirty = false; +} diff --git a/libs/rs/rsFBOCache.h b/libs/rs/rsFBOCache.h new file mode 100644 index 0000000..f42e1f3 --- /dev/null +++ b/libs/rs/rsFBOCache.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef ANDROID_FRAME_BUFFER_OBJECT_CACHE_H +#define ANDROID_FRAME_BUFFER_OBJECT_CACHE_H + +#include "rsObjectBase.h" + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Allocation; + +class FBOCache { +public: + FBOCache(); + ~FBOCache(); + + void init(Context *rsc); + void deinit(Context *rsc); + + void bindColorTarget(Context *rsc, Allocation *a, uint32_t slot); + void bindDepthTarget(Context *, Allocation *a); + void resetAll(Context *); + + void setup(Context *); + + struct Hal { + mutable void *drv; + + struct State { + ObjectBaseRef<Allocation> *colorTargets; + uint32_t colorTargetsCount; + ObjectBaseRef<Allocation> depthTarget; + }; + State state; + }; + Hal mHal; + +protected: + bool mDirty; + void checkError(Context *); + void setColorAttachment(Context *rsc); + void setDepthAttachment(Context *rsc); + bool renderToFramebuffer(); + +}; + +} // renderscript +} // android + +#endif //ANDROID_FRAME_BUFFER_OBJECT_CACHE_H diff --git a/libs/rs/rsFifo.cpp b/libs/rs/rsFifo.cpp new file mode 100644 index 0000000..3d5d8c4 --- /dev/null +++ b/libs/rs/rsFifo.cpp @@ -0,0 +1,31 @@ +/* + * 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 new file mode 100644 index 0000000..f924b95 --- /dev/null +++ b/libs/rs/rsFifo.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef ANDROID_RS_FIFO_H +#define ANDROID_RS_FIFO_H + + +#include "rsUtils.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 Fifo { +protected: + Fifo(); + virtual ~Fifo(); + +public: + void virtual writeAsync(const void *data, size_t bytes) = 0; + void virtual writeWaitReturn(void *ret, size_t retSize) = 0; + size_t virtual read(void *data, size_t bytes) = 0; + void virtual readReturn(const void *data, size_t bytes) = 0; + + void virtual flush() = 0; + +}; + +} +} +#endif diff --git a/libs/rs/rsFifoSocket.cpp b/libs/rs/rsFifoSocket.cpp new file mode 100644 index 0000000..8b8008d --- /dev/null +++ b/libs/rs/rsFifoSocket.cpp @@ -0,0 +1,83 @@ +/* + * 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" + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +using namespace android; +using namespace android::renderscript; + +FifoSocket::FifoSocket() { + sequence = 1; +} + +FifoSocket::~FifoSocket() { + +} + +bool FifoSocket::init() { + int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + return false; +} + +void FifoSocket::shutdown() { +} + +void FifoSocket::writeAsync(const void *data, size_t bytes) { + if (bytes == 0) { + return; + } + //LOGE("writeAsync %p %i", data, bytes); + size_t ret = ::send(sv[0], data, bytes, 0); + //LOGE("writeAsync ret %i", ret); + rsAssert(ret == bytes); +} + +void FifoSocket::writeWaitReturn(void *retData, size_t retBytes) { + //LOGE("writeWaitReturn %p %i", retData, retBytes); + size_t ret = ::recv(sv[0], retData, retBytes, 0); + //LOGE("writeWaitReturn %i", ret); + rsAssert(ret == retBytes); +} + +size_t FifoSocket::read(void *data, size_t bytes) { + //LOGE("read %p %i", data, bytes); + size_t ret = ::recv(sv[1], data, bytes, 0); + rsAssert(ret == bytes); + //LOGE("read ret %i", ret); + return ret; +} + +void FifoSocket::readReturn(const void *data, size_t bytes) { + LOGE("readReturn %p %Zu", data, bytes); + size_t ret = ::send(sv[1], data, bytes, 0); + LOGE("readReturn %Zu", ret); + rsAssert(ret == bytes); +} + + +void FifoSocket::flush() { +} + + diff --git a/libs/rs/rsFifoSocket.h b/libs/rs/rsFifoSocket.h new file mode 100644 index 0000000..7df2b67 --- /dev/null +++ b/libs/rs/rsFifoSocket.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef ANDROID_RS_FIFO_SOCKET_H +#define ANDROID_RS_FIFO_SOCKET_H + + +#include "rsFifo.h" + +namespace android { +namespace renderscript { + + +class FifoSocket { +public: + FifoSocket(); + virtual ~FifoSocket(); + + bool init(); + void shutdown(); + + + + 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(); + +protected: + int sv[2]; + uint32_t sequence; + + +}; + +} +} + +#endif diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index 01dbab8..ce674f4 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -21,14 +21,11 @@ #include "rsProgramFragment.h" #include <cutils/properties.h> +#ifndef ANDROID_RS_SERIALIZE #include <ft2build.h> #include FT_FREETYPE_H #include FT_BITMAP_H - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> +#endif //ANDROID_RS_SERIALIZE using namespace android; using namespace android::renderscript; @@ -40,6 +37,7 @@ Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) { } bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) { +#ifndef ANDROID_RS_SERIALIZE if (mInitialized) { LOGE("Reinitialization of fonts not supported"); return false; @@ -70,6 +68,7 @@ bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data mHasKerning = FT_HAS_KERNING(mFace); mInitialized = true; +#endif //ANDROID_RS_SERIALIZE return true; } @@ -235,6 +234,7 @@ Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { } void Font::updateGlyphCache(CachedGlyphInfo *glyph) { +#ifndef ANDROID_RS_SERIALIZE FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); if (error) { LOGE("Couldn't load glyph."); @@ -275,15 +275,16 @@ void Font::updateGlyphCache(CachedGlyphInfo *glyph) { glyph->mBitmapMinV = (float)startY / (float)cacheHeight; glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; +#endif //ANDROID_RS_SERIALIZE } Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) { CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); - +#ifndef ANDROID_RS_SERIALIZE newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); newGlyph->mIsValid = false; - +#endif //ANDROID_RS_SERIALIZE updateGlyphCache(newGlyph); return newGlyph; @@ -314,9 +315,11 @@ Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi } Font::~Font() { +#ifndef ANDROID_RS_SERIALIZE if (mFace) { FT_Done_Face(mFace); } +#endif for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); @@ -329,7 +332,9 @@ FontState::FontState() { mMaxNumberOfQuads = 1024; mCurrentQuadIndex = 0; mRSC = NULL; +#ifndef ANDROID_RS_SERIALIZE mLibrary = NULL; +#endif //ANDROID_RS_SERIALIZE // Get the renderer properties char property[PROPERTY_VALUE_MAX]; @@ -368,7 +373,7 @@ FontState::~FontState() { rsAssert(!mActiveFonts.size()); } - +#ifndef ANDROID_RS_SERIALIZE FT_Library FontState::getLib() { if (!mLibrary) { FT_Error error = FT_Init_FreeType(&mLibrary); @@ -380,6 +385,8 @@ FT_Library FontState::getLib() { return mLibrary; } +#endif //ANDROID_RS_SERIALIZE + void FontState::init(Context *rsc) { mRSC = rsc; @@ -398,6 +405,7 @@ void FontState::flushAllAndInvalidate() { } } +#ifndef ANDROID_RS_SERIALIZE bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) { // If the glyph is too tall, don't cache it if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { @@ -457,7 +465,8 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r // This will dirty the texture and the shader so next time // we draw it will upload the data - mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT); + + mTextTexture->sendDirty(mRSC); mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); // Some debug code @@ -470,6 +479,7 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r return true; } +#endif //ANDROID_RS_SERIALIZE void FontState::initRenderState() { String8 shaderString("varying vec2 varTex0;\n"); @@ -495,7 +505,7 @@ void FontState::initRenderState() { tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE; tmp[3] = RS_TEXTURE_2D; - mFontShaderFConstant.set(new Allocation(mRSC, inputType, + mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS)); ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(), tmp, 4); @@ -507,12 +517,13 @@ void FontState::initRenderState() { mFontSampler.set(sampler); mFontShaderF->bindSampler(mRSC, 0, sampler); - ProgramStore *fontStore = new ProgramStore(mRSC); + ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true, + false, false, + RS_BLEND_SRC_SRC_ALPHA, + RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, + RS_DEPTH_FUNC_ALWAYS); mFontProgramStore.set(fontStore); - mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); - mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); - mFontProgramStore->setDitherEnable(false); - mFontProgramStore->setDepthMask(false); + mFontProgramStore->init(); } void FontState::initTextTexture() { @@ -521,7 +532,8 @@ void FontState::initTextTexture() { // We will allocate a texture to initially hold 32 character bitmaps Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false); - Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE); + Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE); mTextTexture.set(cacheAlloc); mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT); @@ -549,7 +561,9 @@ void FontState::initVertexArrayBuffers() { uint32_t numIndicies = mMaxNumberOfQuads * 6; Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false); - Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX); + Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType, + RS_ALLOCATION_USAGE_SCRIPT | + RS_ALLOCATION_USAGE_GRAPHICS_VERTEX); uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); // Four verts, two triangles , six indices per quad @@ -566,8 +580,7 @@ void FontState::initVertexArrayBuffers() { indexPtr[i6 + 5] = i4 + 3; } - indexAlloc->deferedUploadToBufferObject(mRSC); - mIndexBuffer.set(indexAlloc); + indexAlloc->sendDirty(mRSC); const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); @@ -581,10 +594,14 @@ void FontState::initVertexArrayBuffers() { mMaxNumberOfQuads * 4, 0, 0, false, false); - Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX); + Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType, + RS_ALLOCATION_USAGE_SCRIPT); mTextMeshPtr = (float*)vertexAlloc->getPtr(); - mVertexArray.set(vertexAlloc); + mMesh.set(new Mesh(mRSC, 1, 1)); + mMesh->setVertexBuffer(vertexAlloc, 0); + mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0); + mMesh->init(); } // We don't want to allocate anything unless we actually draw text @@ -624,18 +641,7 @@ void FontState::issueDrawCommand() { return; } - float *vtx = (float*)mVertexArray->getPtr(); - float *tex = vtx + 3; - - VertexArray::Attrib attribs[2]; - attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); - attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); - VertexArray va(attribs, 2); - va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); - - mIndexBuffer->uploadCheck(mRSC); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); - glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); + mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6); } void FontState::appendMeshQuad(float x1, float y1, float z1, @@ -786,8 +792,7 @@ void FontState::deinit(Context *rsc) { mFontShaderFConstant.clear(); - mIndexBuffer.clear(); - mVertexArray.clear(); + mMesh.clear(); mFontShaderF.clear(); mFontSampler.clear(); @@ -800,13 +805,15 @@ void FontState::deinit(Context *rsc) { mCacheLines.clear(); mDefault.clear(); - +#ifndef ANDROID_RS_SERIALIZE if (mLibrary) { FT_Done_FreeType( mLibrary ); mLibrary = NULL; } +#endif //ANDROID_RS_SERIALIZE } +#ifndef ANDROID_RS_SERIALIZE bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) { if ((uint32_t)bitmap->rows > mMaxHeight) { return false; @@ -822,11 +829,14 @@ bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOri return false; } +#endif //ANDROID_RS_SERIALIZE namespace android { namespace renderscript { -RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) { +RsFont rsi_FontCreateFromFile(Context *rsc, + char const *name, size_t name_length, + float fontSize, uint32_t dpi) { Font *newFont = Font::create(rsc, name, fontSize, dpi); if (newFont) { newFont->incUserRef(); @@ -834,8 +844,11 @@ RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, ui return newFont; } -RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) { - Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen); +RsFont rsi_FontCreateFromMemory(Context *rsc, + char const *name, size_t name_length, + float fontSize, uint32_t dpi, + const void *data, size_t data_length) { + Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length); if (newFont) { newFont->incUserRef(); } diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h index 91a5da9..b0e1430 100644 --- a/libs/rs/rsFont.h +++ b/libs/rs/rsFont.h @@ -199,8 +199,10 @@ protected: float mWhiteThreshold; // Free type library, we only need one copy +#ifndef ANDROID_RS_SERIALIZE FT_LibraryRec_ *mLibrary; FT_LibraryRec_ *getLib(); +#endif //ANDROID_RS_SERIALIZE Vector<Font*> mActiveFonts; // Render state for the font @@ -217,7 +219,9 @@ protected: return (uint8_t*)mTextTexture->getPtr(); } +#ifndef ANDROID_RS_SERIALIZE bool cacheBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY); +#endif //ANDROID_RS_SERIALIZE const Type* getCacheTextureType() { return mTextTexture->getType(); } @@ -230,9 +234,7 @@ protected: uint32_t mMaxNumberOfQuads; void initVertexArrayBuffers(); - ObjectBaseRef<Allocation> mIndexBuffer; - ObjectBaseRef<Allocation> mVertexArray; - + ObjectBaseRef<Mesh> mMesh; bool mInitialized; diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h deleted file mode 100644 index 57da10a..0000000 --- a/libs/rs/rsHandcode.h +++ /dev/null @@ -1,96 +0,0 @@ - -#define DATA_SYNC_SIZE 1024 - -static inline void rsHCAPI_ContextFinish (RsContext rsc) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_ContextFinish); - io->mToCore.commitSync(RS_CMD_ID_ContextFinish, size); -} - -static inline void rsHCAPI_ScriptInvokeV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_ScriptInvokeV); - if (sizeBytes < DATA_SYNC_SIZE) { - size += (sizeBytes + 3) & ~3; - } - RS_CMD_ScriptInvokeV *cmd = static_cast<RS_CMD_ScriptInvokeV *>(io->mToCore.reserve(size)); - cmd->s = va; - cmd->slot = slot; - cmd->dataLen = sizeBytes; - cmd->data = data; - if (sizeBytes < DATA_SYNC_SIZE) { - cmd->data = (void *)(cmd+1); - memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_ScriptInvokeV, size); - } else { - io->mToCore.commitSync(RS_CMD_ID_ScriptInvokeV, size); - } -} - - -static inline void rsHCAPI_ScriptSetVarV (RsContext rsc, RsScript va, uint32_t slot, const void * data, uint32_t sizeBytes) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_ScriptSetVarV); - if (sizeBytes < DATA_SYNC_SIZE) { - size += (sizeBytes + 3) & ~3; - } - RS_CMD_ScriptSetVarV *cmd = static_cast<RS_CMD_ScriptSetVarV *>(io->mToCore.reserve(size)); - cmd->s = va; - cmd->slot = slot; - cmd->dataLen = sizeBytes; - cmd->data = data; - if (sizeBytes < DATA_SYNC_SIZE) { - cmd->data = (void *)(cmd+1); - memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_ScriptSetVarV, size); - } else { - io->mToCore.commitSync(RS_CMD_ID_ScriptSetVarV, size); - } -} - -static inline void rsHCAPI_Allocation1DData (RsContext rsc, RsAllocation va, uint32_t xoff, uint32_t lod, - uint32_t count, const void * data, uint32_t sizeBytes) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_Allocation1DData); - if (sizeBytes < DATA_SYNC_SIZE) { - size += (sizeBytes + 3) & ~3; - } - RS_CMD_Allocation1DData *cmd = static_cast<RS_CMD_Allocation1DData *>(io->mToCore.reserve(size)); - cmd->va = va; - cmd->xoff = xoff; - cmd->lod = lod; - cmd->count = count; - cmd->data = data; - cmd->bytes = sizeBytes; - if (sizeBytes < DATA_SYNC_SIZE) { - cmd->data = (void *)(cmd+1); - memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_Allocation1DData, size); - } else { - io->mToCore.commitSync(RS_CMD_ID_Allocation1DData, size); - } -} - -static inline void rsHCAPI_Allocation1DElementData (RsContext rsc, RsAllocation va, uint32_t x, uint32_t lod, - const void * data, uint32_t comp_offset, uint32_t sizeBytes) { - ThreadIO *io = &((Context *)rsc)->mIO; - uint32_t size = sizeof(RS_CMD_Allocation1DElementData); - if (sizeBytes < DATA_SYNC_SIZE) { - size += (sizeBytes + 3) & ~3; - } - RS_CMD_Allocation1DElementData *cmd = static_cast<RS_CMD_Allocation1DElementData *>(io->mToCore.reserve(size)); - cmd->va = va; - cmd->x = x; - cmd->lod = lod; - cmd->data = data; - cmd->comp_offset = comp_offset; - cmd->bytes = sizeBytes; - if (sizeBytes < DATA_SYNC_SIZE) { - cmd->data = (void *)(cmd+1); - memcpy(cmd+1, data, sizeBytes); - io->mToCore.commit(RS_CMD_ID_Allocation1DElementData, size); - } else { - io->mToCore.commitSync(RS_CMD_ID_Allocation1DElementData, size); - } -} - diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp deleted file mode 100644 index ca41886..0000000 --- a/libs/rs/rsMatrix.cpp +++ /dev/null @@ -1,155 +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 "rsMatrix.h" - -#include "stdlib.h" -#include "string.h" -#include "math.h" - -using namespace android; -using namespace android::renderscript; - -void Matrix::loadIdentity() { - set(0, 0, 1); - set(1, 0, 0); - set(2, 0, 0); - set(3, 0, 0); - - set(0, 1, 0); - set(1, 1, 1); - set(2, 1, 0); - set(3, 1, 0); - - set(0, 2, 0); - set(1, 2, 0); - set(2, 2, 1); - set(3, 2, 0); - - set(0, 3, 0); - set(1, 3, 0); - set(2, 3, 0); - set(3, 3, 1); -} - -void Matrix::load(const float *v) { - memcpy(m, v, sizeof(m)); -} - -void Matrix::load(const Matrix *v) { - memcpy(m, v->m, sizeof(m)); -} - -void Matrix::loadRotate(float rot, float x, float y, float z) { - float c, s; - m[3] = 0; - m[7] = 0; - m[11]= 0; - m[12]= 0; - m[13]= 0; - m[14]= 0; - m[15]= 1; - rot *= float(M_PI / 180.0f); - c = cosf(rot); - s = sinf(rot); - - const float len = sqrtf(x*x + y*y + z*z); - if (len != 1) { - const float recipLen = 1.f / len; - x *= recipLen; - y *= recipLen; - z *= recipLen; - } - const float nc = 1.0f - c; - const float xy = x * y; - const float yz = y * z; - const float zx = z * x; - const float xs = x * s; - const float ys = y * s; - const float zs = z * s; - m[ 0] = x*x*nc + c; - m[ 4] = xy*nc - zs; - m[ 8] = zx*nc + ys; - m[ 1] = xy*nc + zs; - m[ 5] = y*y*nc + c; - m[ 9] = yz*nc - xs; - m[ 2] = zx*nc - ys; - m[ 6] = yz*nc + xs; - m[10] = z*z*nc + c; -} - -void Matrix::loadScale(float x, float y, float z) { - loadIdentity(); - m[0] = x; - m[5] = y; - m[10] = z; -} - -void Matrix::loadTranslate(float x, float y, float z) { - loadIdentity(); - m[12] = x; - m[13] = y; - m[14] = z; -} - -void Matrix::loadMultiply(const Matrix *lhs, const Matrix *rhs) { - for (int i=0 ; i<4 ; i++) { - float ri0 = 0; - float ri1 = 0; - float ri2 = 0; - float ri3 = 0; - for (int j=0 ; j<4 ; j++) { - const float rhs_ij = rhs->get(i,j); - ri0 += lhs->get(j,0) * rhs_ij; - ri1 += lhs->get(j,1) * rhs_ij; - ri2 += lhs->get(j,2) * rhs_ij; - ri3 += lhs->get(j,3) * rhs_ij; - } - set(i,0, ri0); - set(i,1, ri1); - set(i,2, ri2); - set(i,3, ri3); - } -} - -void Matrix::loadOrtho(float l, float r, float b, float t, float n, float f) { - loadIdentity(); - m[0] = 2 / (r - l); - m[5] = 2 / (t - b); - m[10]= -2 / (f - n); - m[12]= -(r + l) / (r - l); - m[13]= -(t + b) / (t - b); - m[14]= -(f + n) / (f - n); -} - -void Matrix::loadFrustum(float l, float r, float b, float t, float n, float f) { - loadIdentity(); - m[0] = 2 * n / (r - l); - m[5] = 2 * n / (t - b); - m[8] = (r + l) / (r - l); - m[9] = (t + b) / (t - b); - m[10]= -(f + n) / (f - n); - m[11]= -1; - m[14]= -2*f*n / (f - n); - m[15]= 0; -} - -void Matrix::vectorMultiply(float *out, const float *in) const { - out[0] = (m[0] * in[0]) + (m[4] * in[1]) + (m[8] * in[2]) + m[12]; - out[1] = (m[1] * in[0]) + (m[5] * in[1]) + (m[9] * in[2]) + m[13]; - out[2] = (m[2] * in[0]) + (m[6] * in[1]) + (m[10] * in[2]) + m[14]; - out[3] = (m[3] * in[0]) + (m[7] * in[1]) + (m[11] * in[2]) + m[15]; -} diff --git a/libs/rs/rsMatrix2x2.cpp b/libs/rs/rsMatrix2x2.cpp new file mode 100644 index 0000000..622113c --- /dev/null +++ b/libs/rs/rsMatrix2x2.cpp @@ -0,0 +1,63 @@ +/* + * 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 "rsMatrix2x2.h" +#include "rsMatrix3x3.h" +#include "rsMatrix4x4.h" + +#include "stdlib.h" +#include "string.h" +#include "math.h" + +using namespace android; +using namespace android::renderscript; + + +void Matrix2x2::loadIdentity() { + m[0] = 1.f; + m[1] = 0.f; + m[2] = 0.f; + m[3] = 1.f; +} + +void Matrix2x2::load(const float *v) { + memcpy(m, v, sizeof(m)); +} + +void Matrix2x2::load(const rs_matrix2x2 *v) { + memcpy(m, v->m, sizeof(m)); +} + +void Matrix2x2::loadMultiply(const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) { + for (int i=0 ; i<2 ; i++) { + float ri0 = 0; + float ri1 = 0; + for (int j=0 ; j<2 ; j++) { + const float rhs_ij = ((const Matrix2x2 *)rhs)->get(i, j); + ri0 += ((const Matrix2x2 *)lhs)->get(j, 0) * rhs_ij; + ri1 += ((const Matrix2x2 *)lhs)->get(j, 1) * rhs_ij; + } + set(i, 0, ri0); + set(i, 1, ri1); + } +} + +void Matrix2x2::transpose() { + float temp = m[1]; + m[1] = m[2]; + m[2] = temp; +} + diff --git a/libs/rs/rsMatrix2x2.h b/libs/rs/rsMatrix2x2.h new file mode 100644 index 0000000..4dcb84a --- /dev/null +++ b/libs/rs/rsMatrix2x2.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#ifndef ANDROID_RS_MATRIX_2x2_H +#define ANDROID_RS_MATRIX_2x2_H + +#include "rsType.h" + + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +struct Matrix2x2 : public rs_matrix2x2 { + inline float get(uint32_t row, uint32_t col) const { + return m[row*2 + col]; + } + + inline void set(uint32_t row, uint32_t col, float v) { + m[row*2 + col] = v; + } + + void loadIdentity(); + void load(const float *); + void load(const rs_matrix2x2 *); + + void loadMultiply(const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs); + + void transpose(); + + void multiply(const rs_matrix2x2 *rhs) { + Matrix2x2 tmp; + tmp.loadMultiply(this, rhs); + load(&tmp); + } +}; + +} +} + + + + +#endif + + + + + diff --git a/libs/rs/rsMatrix3x3.cpp b/libs/rs/rsMatrix3x3.cpp new file mode 100644 index 0000000..3f9a2d1 --- /dev/null +++ b/libs/rs/rsMatrix3x3.cpp @@ -0,0 +1,76 @@ +/* + * 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 "rsMatrix2x2.h" +#include "rsMatrix3x3.h" +#include "rsMatrix4x4.h" + +#include "stdlib.h" +#include "string.h" +#include "math.h" + +using namespace android; +using namespace android::renderscript; + +void Matrix3x3::loadIdentity() { + m[0] = 1.f; + m[1] = 0.f; + m[2] = 0.f; + m[3] = 0.f; + m[4] = 1.f; + m[5] = 0.f; + m[6] = 0.f; + m[7] = 0.f; + m[8] = 1.f; +} + +void Matrix3x3::load(const float *v) { + memcpy(m, v, sizeof(m)); +} + +void Matrix3x3::load(const rs_matrix3x3 *v) { + memcpy(m, v->m, sizeof(m)); +} + +void Matrix3x3::loadMultiply(const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) { + for (int i=0 ; i<3 ; i++) { + float ri0 = 0; + float ri1 = 0; + float ri2 = 0; + for (int j=0 ; j<3 ; j++) { + const float rhs_ij = ((const Matrix3x3 *)rhs)->get(i, j); + ri0 += ((const Matrix3x3 *)lhs)->get(j, 0) * rhs_ij; + ri1 += ((const Matrix3x3 *)lhs)->get(j, 1) * rhs_ij; + ri2 += ((const Matrix3x3 *)lhs)->get(j, 2) * rhs_ij; + } + set(i, 0, ri0); + set(i, 1, ri1); + set(i, 2, ri2); + } +} + +void Matrix3x3::transpose() { + int i, j; + float temp; + for (i = 0; i < 2; ++i) { + for (j = i + 1; j < 3; ++j) { + temp = get(i, j); + set(i, j, get(j, i)); + set(j, i, temp); + } + } +} + diff --git a/libs/rs/rsMatrix3x3.h b/libs/rs/rsMatrix3x3.h new file mode 100644 index 0000000..f96d270 --- /dev/null +++ b/libs/rs/rsMatrix3x3.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#ifndef ANDROID_RS_MATRIX_3x3_H +#define ANDROID_RS_MATRIX_3x3_H + +#include "rsType.h" + + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +struct Matrix3x3 : public rs_matrix3x3 { + inline float get(uint32_t row, uint32_t col) const { + return m[row*3 + col]; + } + + inline void set(uint32_t row, uint32_t col, float v) { + m[row*3 + col] = v; + } + + void loadIdentity(); + void load(const float *); + void load(const rs_matrix3x3 *); + + void loadMultiply(const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs); + + void transpose(); + + void multiply(const rs_matrix3x3 *rhs) { + Matrix3x3 tmp; + tmp.loadMultiply(this, rhs); + load(&tmp); + } +}; + +} +} + + + + +#endif + + + + + diff --git a/libs/rs/rsMatrix4x4.cpp b/libs/rs/rsMatrix4x4.cpp new file mode 100644 index 0000000..f34af47 --- /dev/null +++ b/libs/rs/rsMatrix4x4.cpp @@ -0,0 +1,314 @@ +/* + * 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 "rsMatrix2x2.h" +#include "rsMatrix3x3.h" +#include "rsMatrix4x4.h" + +#include "stdlib.h" +#include "string.h" +#include "math.h" + +using namespace android; +using namespace android::renderscript; + +////////////////////////////////////////////////////////////////////////////// +// Heavy math functions +////////////////////////////////////////////////////////////////////////////// + + + + + +// Returns true if the matrix was successfully inversed +bool Matrix4x4::inverse() { + rs_matrix4x4 result; + + int i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + // computeCofactor for int i, int j + int c0 = (i+1) % 4; + int c1 = (i+2) % 4; + int c2 = (i+3) % 4; + int r0 = (j+1) % 4; + int r1 = (j+2) % 4; + int r2 = (j+3) % 4; + + float minor = + (m[c0 + 4*r0] * (m[c1 + 4*r1] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r1])) + - (m[c0 + 4*r1] * (m[c1 + 4*r0] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r0])) + + (m[c0 + 4*r2] * (m[c1 + 4*r0] * m[c2 + 4*r1] - m[c1 + 4*r1] * m[c2 + 4*r0])); + + float cofactor = (i+j) & 1 ? -minor : minor; + + result.m[4*i + j] = cofactor; + } + } + + // Dot product of 0th column of source and 0th row of result + float det = m[0]*result.m[0] + m[4]*result.m[1] + + m[8]*result.m[2] + m[12]*result.m[3]; + + if (fabs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (i = 0; i < 16; ++i) { + m[i] = result.m[i] * det; + } + + return true; +} + +// Returns true if the matrix was successfully inversed +bool Matrix4x4::inverseTranspose() { + rs_matrix4x4 result; + + int i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + // computeCofactor for int i, int j + int c0 = (i+1) % 4; + int c1 = (i+2) % 4; + int c2 = (i+3) % 4; + int r0 = (j+1) % 4; + int r1 = (j+2) % 4; + int r2 = (j+3) % 4; + + float minor = (m[c0 + 4*r0] * (m[c1 + 4*r1] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r1])) + - (m[c0 + 4*r1] * (m[c1 + 4*r0] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r0])) + + (m[c0 + 4*r2] * (m[c1 + 4*r0] * m[c2 + 4*r1] - m[c1 + 4*r1] * m[c2 + 4*r0])); + + float cofactor = (i+j) & 1 ? -minor : minor; + + result.m[4*j + i] = cofactor; + } + } + + // Dot product of 0th column of source and 0th column of result + float det = m[0]*result.m[0] + m[4]*result.m[4] + + m[8]*result.m[8] + m[12]*result.m[12]; + + if (fabs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (i = 0; i < 16; ++i) { + m[i] = result.m[i] * det; + } + + return true; +} + +void Matrix4x4::transpose() { + int i, j; + float temp; + for (i = 0; i < 3; ++i) { + for (j = i + 1; j < 4; ++j) { + temp = m[i*4 + j]; + m[i*4 + j] = m[j*4 + i]; + m[j*4 + i] = temp; + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////// + +void Matrix4x4::loadIdentity() { + m[0] = 1.f; + m[1] = 0.f; + m[2] = 0.f; + m[3] = 0.f; + m[4] = 0.f; + m[5] = 1.f; + m[6] = 0.f; + m[7] = 0.f; + m[8] = 0.f; + m[9] = 0.f; + m[10] = 1.f; + m[11] = 0.f; + m[12] = 0.f; + m[13] = 0.f; + m[14] = 0.f; + m[15] = 1.f; +} + +void Matrix4x4::load(const float *v) { + memcpy(m, v, sizeof(m)); +} + +void Matrix4x4::load(const rs_matrix4x4 *v) { + memcpy(m, v->m, sizeof(m)); +} + +void Matrix4x4::load(const rs_matrix3x3 *v) { + m[0] = v->m[0]; + m[1] = v->m[1]; + m[2] = v->m[2]; + m[3] = 0.f; + m[4] = v->m[3]; + m[5] = v->m[4]; + m[6] = v->m[5]; + m[7] = 0.f; + m[8] = v->m[6]; + m[9] = v->m[7]; + m[10] = v->m[8]; + m[11] = 0.f; + m[12] = 0.f; + m[13] = 0.f; + m[14] = 0.f; + m[15] = 1.f; +} + +void Matrix4x4::load(const rs_matrix2x2 *v) { + m[0] = v->m[0]; + m[1] = v->m[1]; + m[2] = 0.f; + m[3] = 0.f; + m[4] = v->m[2]; + m[5] = v->m[3]; + m[6] = 0.f; + m[7] = 0.f; + m[8] = 0.f; + m[9] = 0.f; + m[10] = 1.f; + m[11] = 0.f; + m[12] = 0.f; + m[13] = 0.f; + m[14] = 0.f; + m[15] = 1.f; +} + + +void Matrix4x4::loadRotate(float rot, float x, float y, float z) { + float c, s; + m[3] = 0; + m[7] = 0; + m[11]= 0; + m[12]= 0; + m[13]= 0; + m[14]= 0; + m[15]= 1; + rot *= float(M_PI / 180.0f); + c = cosf(rot); + s = sinf(rot); + + const float len = x*x + y*y + z*z; + if (len != 1) { + const float recipLen = 1.f / sqrtf(len); + x *= recipLen; + y *= recipLen; + z *= recipLen; + } + const float nc = 1.0f - c; + const float xy = x * y; + const float yz = y * z; + const float zx = z * x; + const float xs = x * s; + const float ys = y * s; + const float zs = z * s; + m[ 0] = x*x*nc + c; + m[ 4] = xy*nc - zs; + m[ 8] = zx*nc + ys; + m[ 1] = xy*nc + zs; + m[ 5] = y*y*nc + c; + m[ 9] = yz*nc - xs; + m[ 2] = zx*nc - ys; + m[ 6] = yz*nc + xs; + m[10] = z*z*nc + c; +} + +void Matrix4x4::loadScale(float x, float y, float z) { + loadIdentity(); + set(0, 0, x); + set(1, 1, y); + set(2, 2, z); +} + +void Matrix4x4::loadTranslate(float x, float y, float z) { + loadIdentity(); + m[12] = x; + m[13] = y; + m[14] = z; +} + +void Matrix4x4::loadMultiply(const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) { + for (int i=0 ; i<4 ; i++) { + float ri0 = 0; + float ri1 = 0; + float ri2 = 0; + float ri3 = 0; + for (int j=0 ; j<4 ; j++) { + const float rhs_ij = ((const Matrix4x4 *)rhs)->get(i,j); + ri0 += ((const Matrix4x4 *)lhs)->get(j,0) * rhs_ij; + ri1 += ((const Matrix4x4 *)lhs)->get(j,1) * rhs_ij; + ri2 += ((const Matrix4x4 *)lhs)->get(j,2) * rhs_ij; + ri3 += ((const Matrix4x4 *)lhs)->get(j,3) * rhs_ij; + } + set(i,0, ri0); + set(i,1, ri1); + set(i,2, ri2); + set(i,3, ri3); + } +} + +void Matrix4x4::loadOrtho(float left, float right, float bottom, float top, float near, float far) { + loadIdentity(); + m[0] = 2.f / (right - left); + m[5] = 2.f / (top - bottom); + m[10]= -2.f / (far - near); + m[12]= -(right + left) / (right - left); + m[13]= -(top + bottom) / (top - bottom); + m[14]= -(far + near) / (far - near); +} + +void Matrix4x4::loadFrustum(float left, float right, float bottom, float top, float near, float far) { + loadIdentity(); + m[0] = 2.f * near / (right - left); + m[5] = 2.f * near / (top - bottom); + m[8] = (right + left) / (right - left); + m[9] = (top + bottom) / (top - bottom); + m[10]= -(far + near) / (far - near); + m[11]= -1.f; + m[14]= -2.f * far * near / (far - near); + m[15]= 0.f; +} + +void Matrix4x4::loadPerspective(float fovy, float aspect, float near, float far) { + float top = near * tan((float) (fovy * M_PI / 360.0f)); + float bottom = -top; + float left = bottom * aspect; + float right = top * aspect; + loadFrustum(left, right, bottom, top, near, far); +} + +void Matrix4x4::vectorMultiply(float *out, const float *in) const { + out[0] = (m[0] * in[0]) + (m[4] * in[1]) + (m[8] * in[2]) + m[12]; + out[1] = (m[1] * in[0]) + (m[5] * in[1]) + (m[9] * in[2]) + m[13]; + out[2] = (m[2] * in[0]) + (m[6] * in[1]) + (m[10] * in[2]) + m[14]; + out[3] = (m[3] * in[0]) + (m[7] * in[1]) + (m[11] * in[2]) + m[15]; +} + +void Matrix4x4::logv(const char *s) const { + LOGV("%s {%f, %f, %f, %f", s, m[0], m[4], m[8], m[12]); + LOGV("%s %f, %f, %f, %f", s, m[1], m[5], m[9], m[13]); + LOGV("%s %f, %f, %f, %f", s, m[2], m[6], m[10], m[14]); + LOGV("%s %f, %f, %f, %f}", s, m[3], m[7], m[11], m[15]); +} diff --git a/libs/rs/rsMatrix.h b/libs/rs/rsMatrix4x4.h index 4130b8e..d30184f 100644 --- a/libs/rs/rsMatrix.h +++ b/libs/rs/rsMatrix4x4.h @@ -14,57 +14,66 @@ * limitations under the License. */ -#ifndef ANDROID_RS_MATRIX_H -#define ANDROID_RS_MATRIX_H +#ifndef ANDROID_RS_MATRIX_4x4_H +#define ANDROID_RS_MATRIX_4x4_H +#include "rsType.h" // --------------------------------------------------------------------------- namespace android { namespace renderscript { -struct Matrix { - float m[16]; - - inline float get(int i, int j) const { - return m[i*4 + j]; +struct Matrix4x4 : public rs_matrix4x4 { + float get(uint32_t row, uint32_t col) const { + return m[row*4 + col]; } - inline void set(int i, int j, float v) { - m[i*4 + j] = v; + void set(uint32_t row, uint32_t col, float v) { + m[row*4 + col] = v; } void loadIdentity(); void load(const float *); - void load(const Matrix *); + void load(const rs_matrix4x4 *); + void load(const rs_matrix3x3 *); + void load(const rs_matrix2x2 *); void loadRotate(float rot, float x, float y, float z); void loadScale(float x, float y, float z); void loadTranslate(float x, float y, float z); - void loadMultiply(const Matrix *lhs, const Matrix *rhs); + void loadMultiply(const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs); void loadOrtho(float l, float r, float b, float t, float n, float f); void loadFrustum(float l, float r, float b, float t, float n, float f); + void loadPerspective(float fovy, float aspect, float near, float far); void vectorMultiply(float *v4out, const float *v3in) const; - void multiply(const Matrix *rhs) { - Matrix tmp; + bool inverse(); + bool inverseTranspose(); + void transpose(); + + void logv(const char *s) const; + + + void multiply(const rs_matrix4x4 *rhs) { + Matrix4x4 tmp; tmp.loadMultiply(this, rhs); load(&tmp); } void rotate(float rot, float x, float y, float z) { - Matrix tmp; + Matrix4x4 tmp; tmp.loadRotate(rot, x, y, z); multiply(&tmp); } void scale(float x, float y, float z) { - Matrix tmp; + Matrix4x4 tmp; tmp.loadScale(x, y, z); multiply(&tmp); } void translate(float x, float y, float z) { - Matrix tmp; + Matrix4x4 tmp; tmp.loadTranslate(x, y, z); multiply(&tmp); } diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index 76fe62d..359d09f 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -15,46 +15,53 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES2/gl2.h> -#include <GLES/glext.h> -#endif using namespace android; using namespace android::renderscript; Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { - mPrimitives = NULL; - mPrimitivesCount = 0; - mVertexBuffers = NULL; - mVertexBufferCount = 0; - -#ifndef ANDROID_RS_SERIALIZE - mAttribs = NULL; - mAttribAllocationIndex = NULL; + mHal.drv = NULL; + mHal.state.primitives = NULL; + mHal.state.primitivesCount = 0; + mHal.state.vertexBuffers = NULL; + mHal.state.vertexBuffersCount = 0; + mInitialized = false; +} - mAttribCount = 0; -#endif +Mesh::Mesh(Context *rsc, + uint32_t vertexBuffersCount, + uint32_t primitivesCount) : ObjectBase(rsc) { + mHal.drv = NULL; + mHal.state.primitivesCount = primitivesCount; + mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount]; + for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { + mHal.state.primitives[i] = new Primitive_t; + } + mHal.state.vertexBuffersCount = vertexBuffersCount; + mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount]; } Mesh::~Mesh() { - if (mVertexBuffers) { - delete[] mVertexBuffers; +#ifndef ANDROID_RS_SERIALIZE + mRSC->mHal.funcs.mesh.destroy(mRSC, this); +#endif + + if (mHal.state.vertexBuffers) { + delete[] mHal.state.vertexBuffers; } - if (mPrimitives) { - for (uint32_t i = 0; i < mPrimitivesCount; i ++) { - delete mPrimitives[i]; + if (mHal.state.primitives) { + for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { + mHal.state.primitives[i]->mIndexBuffer.clear(); + delete mHal.state.primitives[i]; } - delete[] mPrimitives; + delete[] mHal.state.primitives; } +} +void Mesh::init() { #ifndef ANDROID_RS_SERIALIZE - if (mAttribs) { - delete[] mAttribs; - delete[] mAttribAllocationIndex; - } + mRSC->mHal.funcs.mesh.init(mRSC, this); #endif } @@ -66,15 +73,15 @@ void Mesh::serialize(OStream *stream) const { stream->addString(&name); // Store number of vertex streams - stream->addU32(mVertexBufferCount); - for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) { - mVertexBuffers[vCount]->serialize(stream); + stream->addU32(mHal.state.vertexBuffersCount); + for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) { + mHal.state.vertexBuffers[vCount]->serialize(stream); } - stream->addU32(mPrimitivesCount); + stream->addU32(mHal.state.primitivesCount); // Store the primitives - for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) { - Primitive_t * prim = mPrimitives[pCount]; + for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) { + Primitive_t * prim = mHal.state.primitives[pCount]; stream->addU8((uint8_t)prim->mPrimitive); @@ -95,213 +102,106 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { return NULL; } - Mesh * mesh = new Mesh(rsc); - String8 name; stream->loadString(&name); - mesh->setName(name.string(), name.size()); - mesh->mVertexBufferCount = stream->loadU32(); - if (mesh->mVertexBufferCount) { - mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount]; + uint32_t vertexBuffersCount = stream->loadU32(); + ObjectBaseRef<Allocation> *vertexBuffers = NULL; + if (vertexBuffersCount) { + vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount]; - for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) { + for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); - mesh->mVertexBuffers[vCount].set(vertexAlloc); + vertexBuffers[vCount].set(vertexAlloc); } } - mesh->mPrimitivesCount = stream->loadU32(); - if (mesh->mPrimitivesCount) { - mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount]; + uint32_t primitivesCount = stream->loadU32(); + ObjectBaseRef<Allocation> *indexBuffers = NULL; + RsPrimitive *primitives = NULL; + if (primitivesCount) { + indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount]; + primitives = new RsPrimitive[primitivesCount]; // load all primitives - for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) { - Primitive_t * prim = new Primitive_t; - mesh->mPrimitives[pCount] = prim; - - prim->mPrimitive = (RsPrimitive)stream->loadU8(); + for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { + primitives[pCount] = (RsPrimitive)stream->loadU8(); // Check to see if the index buffer was stored uint32_t isIndexPresent = stream->loadU32(); if (isIndexPresent) { Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); - prim->mIndexBuffer.set(indexAlloc); + indexBuffers[pCount].set(indexAlloc); } } } -#ifndef ANDROID_RS_SERIALIZE - mesh->updateGLPrimitives(); - mesh->initVertexAttribs(); - mesh->uploadAll(rsc); -#endif - return mesh; -} - -#ifndef ANDROID_RS_SERIALIZE - -bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { - // Do not create attribs for padding - if (elem->getFieldName(fieldIdx)[0] == '#') { - return false; - } - - // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. - // Filter rs types accordingly - RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); - if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && - dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && - dt != RS_TYPE_SIGNED_16) { - return false; - } - - // Now make sure they are not arrays - uint32_t arraySize = elem->getFieldArraySize(fieldIdx); - if (arraySize != 1) { - return false; + Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount); + mesh->setName(name.string(), name.size()); + for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { + mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount); } - - return true; -} - -void Mesh::initVertexAttribs() { - // Count the number of gl attrs to initialize - mAttribCount = 0; - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Element *elem = mVertexBuffers[ct]->getType()->getElement(); - for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { - if (isValidGLComponent(elem, ct)) { - mAttribCount ++; - } - } + for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { + mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount); } - if (mAttribs) { - delete [] mAttribs; - delete [] mAttribAllocationIndex; - mAttribs = NULL; - mAttribAllocationIndex = NULL; + // Cleanup + if (vertexBuffersCount) { + delete[] vertexBuffers; } - if (!mAttribCount) { - return; + if (primitivesCount) { + delete[] indexBuffers; + delete[] primitives; } - mAttribs = new VertexArray::Attrib[mAttribCount]; - mAttribAllocationIndex = new uint32_t[mAttribCount]; - - uint32_t userNum = 0; - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Element *elem = mVertexBuffers[ct]->getType()->getElement(); - uint32_t stride = elem->getSizeBytes(); - for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { - const Component &c = elem->getField(fieldI)->getComponent(); - - if (!isValidGLComponent(elem, fieldI)) { - continue; - } - - mAttribs[userNum].size = c.getVectorSize(); - mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); - mAttribs[userNum].type = c.getGLType(); - mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); - mAttribs[userNum].stride = stride; - String8 tmp(RS_SHADER_ATTR); - tmp.append(elem->getFieldName(fieldI)); - mAttribs[userNum].name.setTo(tmp.string()); - - // Remember which allocation this attribute came from - mAttribAllocationIndex[userNum] = ct; - userNum ++; - } - } +#ifndef ANDROID_RS_SERIALIZE + mesh->init(); + mesh->uploadAll(rsc); +#endif + return mesh; } void Mesh::render(Context *rsc) const { - for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { + for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { renderPrimitive(rsc, ct); } } void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const { - if (primIndex >= mPrimitivesCount) { + if (primIndex >= mHal.state.primitivesCount) { LOGE("Invalid primitive index"); return; } - Primitive_t *prim = mPrimitives[primIndex]; + Primitive_t *prim = mHal.state.primitives[primIndex]; if (prim->mIndexBuffer.get()) { renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX()); return; } - renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX()); + renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX()); } void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { - if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) { + if (len < 1 || primIndex >= mHal.state.primitivesCount) { LOGE("Invalid mesh or parameters"); return; } - rsc->checkError("Mesh::renderPrimitiveRange 1"); - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - mVertexBuffers[ct]->uploadCheck(rsc); - } - // update attributes with either buffer information or data ptr based on their current state - for (uint32_t ct=0; ct < mAttribCount; ct++) { - uint32_t allocIndex = mAttribAllocationIndex[ct]; - Allocation *alloc = mVertexBuffers[allocIndex].get(); - if (alloc->getIsBufferObject()) { - mAttribs[ct].buffer = alloc->getBufferObjectID(); - mAttribs[ct].ptr = NULL; - } else { - mAttribs[ct].buffer = 0; - mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr(); - } - } - - VertexArray va(mAttribs, mAttribCount); - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - - rsc->checkError("Mesh::renderPrimitiveRange 2"); - Primitive_t *prim = mPrimitives[primIndex]; - if (prim->mIndexBuffer.get()) { - prim->mIndexBuffer->uploadCheck(rsc); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID()); - glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); - } else { - glDrawArrays(prim->mGLPrimitive, start, len); - } - - rsc->checkError("Mesh::renderPrimitiveRange"); + mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len); } - void Mesh::uploadAll(Context *rsc) { - for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) { - if (mVertexBuffers[ct].get()) { - mVertexBuffers[ct]->deferedUploadToBufferObject(rsc); - } - } - - for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { - if (mPrimitives[ct]->mIndexBuffer.get()) { - mPrimitives[ct]->mIndexBuffer->deferedUploadToBufferObject(rsc); + for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) { + if (mHal.state.vertexBuffers[ct].get()) { + rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.vertexBuffers[ct].get()); } } -} -void Mesh::updateGLPrimitives() { - for (uint32_t i = 0; i < mPrimitivesCount; i ++) { - switch (mPrimitives[i]->mPrimitive) { - case RS_PRIMITIVE_POINT: mPrimitives[i]->mGLPrimitive = GL_POINTS; break; - case RS_PRIMITIVE_LINE: mPrimitives[i]->mGLPrimitive = GL_LINES; break; - case RS_PRIMITIVE_LINE_STRIP: mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE: mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break; - case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE_FAN: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break; + for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { + if (mHal.state.primitives[ct]->mIndexBuffer.get()) { + rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.primitives[ct]->mIndexBuffer.get()); } } } @@ -312,8 +212,8 @@ void Mesh::computeBBox() { uint32_t stride = 0; uint32_t numVerts = 0; // First we need to find the position ptr and stride - for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { - const Type *bufferType = mVertexBuffers[ct]->getType(); + for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) { + const Type *bufferType = mHal.state.vertexBuffers[ct]->getType(); const Element *bufferElem = bufferType->getElement(); for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) { @@ -321,7 +221,7 @@ void Mesh::computeBBox() { vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize(); stride = bufferElem->getSizeBytes() / sizeof(float); uint32_t offset = bufferElem->getFieldOffsetBytes(ct); - posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset); + posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset); numVerts = bufferType->getDimX(); break; } @@ -352,76 +252,58 @@ void Mesh::computeBBox() { namespace android { namespace renderscript { -RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) { - Mesh *sm = new Mesh(rsc); +RsMesh rsi_MeshCreate(Context *rsc, + RsAllocation * vtx, size_t vtxCount, + RsAllocation * idx, size_t idxCount, + uint32_t * primType, size_t primTypeCount) { + rsAssert(idxCount == primTypeCount); + Mesh *sm = new Mesh(rsc, vtxCount, idxCount); sm->incUserRef(); - sm->mPrimitivesCount = idxCount; - sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount]; - for (uint32_t ct = 0; ct < idxCount; ct ++) { - sm->mPrimitives[ct] = new Mesh::Primitive_t; + for (uint32_t i = 0; i < vtxCount; i ++) { + sm->setVertexBuffer((Allocation*)vtx[i], i); } - sm->mVertexBufferCount = vtxCount; - sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount]; - - return sm; -} - -void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) { - Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(slot < sm->mVertexBufferCount); - - sm->mVertexBuffers[slot].set((Allocation *)va); -} - -void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) { - Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(slot < sm->mPrimitivesCount); + for (uint32_t i = 0; i < idxCount; i ++) { + sm->setPrimitive((Allocation*)idx[i], (RsPrimitive)primType[i], i); + } - sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va); - sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType; - sm->updateGLPrimitives(); -} + sm->init(); -void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) { - Mesh *sm = static_cast<Mesh *>(mv); - sm->initVertexAttribs(); + return sm; } }} void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) { Mesh *sm = static_cast<Mesh *>(mv); - *numVtx = sm->mVertexBufferCount; + *numVtx = sm->mHal.state.vertexBuffersCount; } void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) { Mesh *sm = static_cast<Mesh *>(mv); - *numIdx = sm->mPrimitivesCount; + *numIdx = sm->mHal.state.primitivesCount; } void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(vtxDataCount == sm->mVertexBufferCount); + rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount); for (uint32_t ct = 0; ct < vtxDataCount; ct ++) { - vtxData[ct] = sm->mVertexBuffers[ct].get(); - sm->mVertexBuffers[ct]->incUserRef(); + vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get(); + sm->mHal.state.vertexBuffers[ct]->incUserRef(); } } void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) { Mesh *sm = static_cast<Mesh *>(mv); - rsAssert(idxDataCount == sm->mPrimitivesCount); + rsAssert(idxDataCount == sm->mHal.state.primitivesCount); for (uint32_t ct = 0; ct < idxDataCount; ct ++) { - va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get(); - primType[ct] = sm->mPrimitives[ct]->mPrimitive; - if (sm->mPrimitives[ct]->mIndexBuffer.get()) { - sm->mPrimitives[ct]->mIndexBuffer->incUserRef(); + va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get(); + primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive; + if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) { + sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef(); } } } - -#endif diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h index 3e080e2..ed1e93d 100644 --- a/libs/rs/rsMesh.h +++ b/libs/rs/rsMesh.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -29,57 +29,58 @@ namespace renderscript { class Mesh : public ObjectBase { public: Mesh(Context *); + Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount); ~Mesh(); - // Contains vertex data - // Position, normal, texcoord, etc could either be strided in one allocation - // of provided separetely in multiple ones - ObjectBaseRef<Allocation> *mVertexBuffers; - uint32_t mVertexBufferCount; - // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference // If both are null, mPrimitive only would be used to render the mesh - struct Primitive_t - { + struct Primitive_t { ObjectBaseRef<Allocation> mIndexBuffer; - RsPrimitive mPrimitive; - uint32_t mGLPrimitive; }; - Primitive_t ** mPrimitives; - uint32_t mPrimitivesCount; - virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } static Mesh *createFromStream(Context *rsc, IStream *stream); + void init(); + + struct Hal { + mutable void *drv; + + struct State { + // Contains vertex data + // Position, normal, texcoord, etc could either be strided in one allocation + // of provided separetely in multiple ones + ObjectBaseRef<Allocation> *vertexBuffers; + uint32_t vertexBuffersCount; + + Primitive_t ** primitives; + uint32_t primitivesCount; + }; + State state; + }; + Hal mHal; + + void setVertexBuffer(Allocation *vb, uint32_t index) { + mHal.state.vertexBuffers[index].set(vb); + } + + void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) { + mHal.state.primitives[index]->mIndexBuffer.set(idx); + mHal.state.primitives[index]->mPrimitive = prim; + } -#ifndef ANDROID_RS_SERIALIZE void render(Context *) const; void renderPrimitive(Context *, uint32_t primIndex) const; void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; void uploadAll(Context *); - void updateGLPrimitives(); - - // Bounding volumes float mBBoxMin[3]; float mBBoxMax[3]; void computeBBox(); - - void initVertexAttribs(); - protected: - bool isValidGLComponent(const Element *elem, uint32_t fieldIdx); - // Attribues that allow us to map to GL - VertexArray::Attrib *mAttribs; - // This allows us to figure out which allocation the attribute - // belongs to. In the event the allocation is uploaded to GL - // buffer, it lets us properly map it - uint32_t *mAttribAllocationIndex; - uint32_t mAttribCount; -#endif + bool mInitialized; }; class MeshContext { @@ -92,7 +93,7 @@ public: } } -#endif //ANDROID_RS_TRIANGLE_MESH_H +#endif //ANDROID_RS_MESH_H diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 4ef05bf..b1d8f48 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -15,64 +15,47 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgram.h" using namespace android; using namespace android::renderscript; -Program::Program(Context *rsc) : ObjectBase(rsc) { - initMemberVars(); -} - Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) - : ObjectBase(rsc) { + : ProgramBase(rsc) { initMemberVars(); for (uint32_t ct=0; ct < paramLength; ct+=2) { if (params[ct] == RS_PROGRAM_PARAM_INPUT) { - mInputCount++; - } - if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) { - mOutputCount++; + mHal.state.inputElementsCount++; } if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { - mConstantCount++; + mHal.state.constantsCount++; } if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { - mTextureCount++; + mHal.state.texturesCount++; } } - mTextures = new ObjectBaseRef<Allocation>[mTextureCount]; - mSamplers = new ObjectBaseRef<Sampler>[mTextureCount]; - mTextureTargets = new RsTextureTarget[mTextureCount]; - mInputElements = new ObjectBaseRef<Element>[mInputCount]; - mOutputElements = new ObjectBaseRef<Element>[mOutputCount]; - mConstantTypes = new ObjectBaseRef<Type>[mConstantCount]; - mConstants = new ObjectBaseRef<Allocation>[mConstantCount]; + mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount]; + mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount]; + mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount]; + mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount]; + mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount]; + mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount]; uint32_t input = 0; - uint32_t output = 0; uint32_t constant = 0; uint32_t texture = 0; for (uint32_t ct=0; ct < paramLength; ct+=2) { if (params[ct] == RS_PROGRAM_PARAM_INPUT) { - mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1])); - } - if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) { - mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1])); + mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1])); } if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) { - mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1])); + mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1])); } if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) { - mTextureTargets[texture++] = (RsTextureTarget)params[ct+1]; + mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1]; } } mIsInternal = false; @@ -84,88 +67,69 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, shaderLength -= internalTokenLen; } mUserShader.setTo(shaderText, shaderLength); - - initAttribAndUniformArray(); } Program::~Program() { - if (mRSC->props.mLogShaders) { - LOGV("Program::~Program with shader id %u", mShaderID); - } - if (mShaderID) { - glDeleteShader(mShaderID); - } - - for (uint32_t ct=0; ct < mConstantCount; ct++) { + for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) { bindAllocation(NULL, NULL, ct); } - for (uint32_t ct=0; ct < mTextureCount; ct++) { + for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) { bindTexture(NULL, ct, NULL); bindSampler(NULL, ct, NULL); } - delete[] mTextures; - delete[] mSamplers; - delete[] mTextureTargets; - delete[] mInputElements; - delete[] mOutputElements; - delete[] mConstantTypes; - delete[] mConstants; - delete[] mAttribNames; - delete[] mUniformNames; - delete[] mUniformArraySizes; - mInputCount = 0; - mOutputCount = 0; - mConstantCount = 0; + delete[] mHal.state.textures; + delete[] mHal.state.samplers; + delete[] mHal.state.textureTargets; + delete[] mHal.state.inputElements; + delete[] mHal.state.constantTypes; + delete[] mHal.state.constants; + mHal.state.inputElementsCount = 0; + mHal.state.constantsCount = 0; + mHal.state.texturesCount = 0; } void Program::initMemberVars() { mDirty = true; - mShaderID = 0; - mAttribCount = 0; - mUniformCount = 0; - mTextureCount = 0; - mTextures = NULL; - mSamplers = NULL; - mTextureTargets = NULL; - mInputElements = NULL; - mOutputElements = NULL; - mConstantTypes = NULL; - mConstants = NULL; - mAttribNames = NULL; - mUniformNames = NULL; - mUniformArraySizes = NULL; - mInputCount = 0; - mOutputCount = 0; - mConstantCount = 0; - mIsValid = false; + mHal.drv = NULL; + mHal.state.textures = NULL; + mHal.state.samplers = NULL; + mHal.state.textureTargets = NULL; + mHal.state.inputElements = NULL; + mHal.state.constantTypes = NULL; + mHal.state.constants = NULL; + + mHal.state.inputElementsCount = 0; + mHal.state.constantsCount = 0; + mHal.state.texturesCount = 0; + mIsInternal = false; } void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { if (alloc != NULL) { - if (slot >= mConstantCount) { + if (slot >= mHal.state.constantsCount) { LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u", - slot, (uint32_t)this, mConstantCount); + slot, (uint32_t)this, mHal.state.constantsCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation"); return; } - if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) { + if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) { LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch", slot, (uint32_t)this); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation"); return; } } - if (mConstants[slot].get() == alloc) { + if (mHal.state.constants[slot].get() == alloc) { return; } - if (mConstants[slot].get()) { - mConstants[slot].get()->removeProgramToDirty(this); + if (mHal.state.constants[slot].get()) { + mHal.state.constants[slot].get()->removeProgramToDirty(this); } - mConstants[slot].set(alloc); + mHal.state.constants[slot].set(alloc); if (alloc) { alloc->addProgramToDirty(this); } @@ -173,327 +137,33 @@ void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { } void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) { - if (slot >= mTextureCount) { - LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount); + if (slot >= mHal.state.texturesCount) { + LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture"); return; } - if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) { + if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) { LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot"); return; } - //LOGE("bindtex %i %p", slot, a); - mTextures[slot].set(a); + mHal.state.textures[slot].set(a); mDirty = true; } void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) { - if (slot >= mTextureCount) { - LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount); + if (slot >= mHal.state.texturesCount) { + LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount); rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler"); return; } - mSamplers[slot].set(s); + mHal.state.samplers[slot].set(s); mDirty = true; } -String8 Program::getGLSLInputString() const { - String8 s; - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *e = mInputElements[ct].get(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - - // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { - case 1: s.append("attribute float ATTRIB_"); break; - case 2: s.append("attribute vec2 ATTRIB_"); break; - case 3: s.append("attribute vec3 ATTRIB_"); break; - case 4: s.append("attribute vec4 ATTRIB_"); break; - default: - rsAssert(0); - } - - s.append(e->getFieldName(field)); - s.append(";\n"); - } - } - return s; -} - -String8 Program::getGLSLOutputString() const { - return String8(); -} - -String8 Program::getGLSLConstantString() const { - return String8(); -} - -void Program::createShader() { -} - -bool Program::loadShader(Context *rsc, uint32_t type) { - mShaderID = glCreateShader(type); - rsAssert(mShaderID); - - if (rsc->props.mLogShaders) { - LOGV("Loading shader type %x, ID %i", type, mShaderID); - LOGV("%s", mShader.string()); - } - - if (mShaderID) { - const char * ss = mShader.string(); - glShaderSource(mShaderID, 1, &ss, NULL); - glCompileShader(mShaderID); - - GLint compiled = 0; - glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLen = 0; - glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen) { - char* buf = (char*) malloc(infoLen); - if (buf) { - glGetShaderInfoLog(mShaderID, infoLen, NULL, buf); - LOGE("Could not compile shader \n%s\n", buf); - free(buf); - } - glDeleteShader(mShaderID); - mShaderID = 0; - rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,"); - return false; - } - } - } - - if (rsc->props.mLogShaders) { - LOGV("--Shader load result %x ", glGetError()); - } - mIsValid = true; - return true; -} - -void Program::setShader(const char *txt, uint32_t len) { - mUserShader.setTo(txt, len); -} - -void Program::appendUserConstants() { - for (uint32_t ct=0; ct < mConstantCount; ct++) { - const Element *e = mConstantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } - - // Cannot be complex - rsAssert(!f->getFieldCount()); - if (f->getType() == RS_TYPE_MATRIX_4X4) { - mShader.append("uniform mat4 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_3X3) { - mShader.append("uniform mat3 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_2X2) { - mShader.append("uniform mat2 UNI_"); - } else { - switch (f->getComponent().getVectorSize()) { - case 1: mShader.append("uniform float UNI_"); break; - case 2: mShader.append("uniform vec2 UNI_"); break; - case 3: mShader.append("uniform vec3 UNI_"); break; - case 4: mShader.append("uniform vec4 UNI_"); break; - default: - rsAssert(0); - } - } - - mShader.append(fn); - if (e->getFieldArraySize(field) > 1) { - mShader.appendFormat("[%d]", e->getFieldArraySize(field)); - } - mShader.append(";\n"); - } - } -} - -void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { - RsDataType dataType = field->getType(); - uint32_t elementSize = field->getSizeBytes() / sizeof(float); - for (uint32_t i = 0; i < arraySize; i ++) { - if (arraySize > 1) { - LOGV("Array Element [%u]", i); - } - if (dataType == RS_TYPE_MATRIX_4X4) { - LOGV("Matrix4x4"); - LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]); - LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]); - LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]); - LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]); - } else if (dataType == RS_TYPE_MATRIX_3X3) { - LOGV("Matrix3x3"); - LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]); - LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]); - LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]); - } else if (dataType == RS_TYPE_MATRIX_2X2) { - LOGV("Matrix2x2"); - LOGV("{%f, %f", fd[0], fd[2]); - LOGV(" %f, %f}", fd[1], fd[3]); - } else { - switch (field->getComponent().getVectorSize()) { - case 1: - LOGV("Uniform 1 = %f", fd[0]); - break; - case 2: - LOGV("Uniform 2 = %f %f", fd[0], fd[1]); - break; - case 3: - LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); - break; - case 4: - LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); - break; - default: - rsAssert(0); - } - } - LOGE("Element size %u data=%p", elementSize, fd); - fd += elementSize; - LOGE("New data=%p", fd); - } -} - -void Program::setUniform(Context *rsc, const Element *field, const float *fd, - int32_t slot, uint32_t arraySize ) { - RsDataType dataType = field->getType(); - if (dataType == RS_TYPE_MATRIX_4X4) { - glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd); - } else if (dataType == RS_TYPE_MATRIX_3X3) { - glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd); - } else if (dataType == RS_TYPE_MATRIX_2X2) { - glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd); - } else { - switch (field->getComponent().getVectorSize()) { - case 1: - glUniform1fv(slot, arraySize, fd); - break; - case 2: - glUniform2fv(slot, arraySize, fd); - break; - case 3: - glUniform3fv(slot, arraySize, fd); - break; - case 4: - glUniform4fv(slot, arraySize, fd); - break; - default: - rsAssert(0); - } - } -} - -void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) { - uint32_t uidx = 0; - for (uint32_t ct=0; ct < mConstantCount; ct++) { - Allocation *alloc = mConstants[ct].get(); - if (!alloc) { - LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct); - rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound"); - continue; - } - - const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); - const Element *e = mConstantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fieldName = e->getFieldName(field); - // If this field is padding, skip it - if (fieldName[0] == '#') { - continue; - } - - uint32_t offset = e->getFieldOffsetBytes(field); - const float *fd = reinterpret_cast<const float *>(&data[offset]); - - int32_t slot = -1; - uint32_t arraySize = 1; - if (!isFragment) { - slot = sc->vtxUniformSlot(uidx); - arraySize = sc->vtxUniformSize(uidx); - } else { - slot = sc->fragUniformSlot(uidx); - arraySize = sc->fragUniformSize(uidx); - } - if (rsc->props.mLogShadersUniforms) { - LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName); - } - uidx ++; - if (slot < 0) { - continue; - } - - if (rsc->props.mLogShadersUniforms) { - logUniform(f, fd, arraySize); - } - setUniform(rsc, f, fd, slot, arraySize); - } - } -} - -void Program::initAttribAndUniformArray() { - mAttribCount = 0; - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *elem = mInputElements[ct].get(); - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mAttribCount ++; - } - } - } - - mUniformCount = 0; - for (uint32_t ct=0; ct < mConstantCount; ct++) { - const Element *elem = mConstantTypes[ct]->getElement(); - - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mUniformCount ++; - } - } - } - mUniformCount += mTextureCount; - - if (mAttribCount) { - mAttribNames = new String8[mAttribCount]; - } - if (mUniformCount) { - mUniformNames = new String8[mUniformCount]; - mUniformArraySizes = new uint32_t[mUniformCount]; - } -} - -void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { - rsAssert(e->getFieldCount()); - for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { - const Element *ce = e->getField(ct); - if (ce->getFieldCount()) { - initAddUserElement(ce, names, arrayLengths, count, prefix); - } else if (e->getFieldName(ct)[0] != '#') { - String8 tmp(prefix); - tmp.append(e->getFieldName(ct)); - names[*count].setTo(tmp.string()); - if (arrayLengths) { - arrayLengths[*count] = e->getFieldArraySize(ct); - } - (*count)++; - } - } -} - namespace android { namespace renderscript { diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index c48464d..948ba3e 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -17,101 +17,68 @@ #ifndef ANDROID_RS_PROGRAM_H #define ANDROID_RS_PROGRAM_H -#include "rsObjectBase.h" +#include "rsProgramBase.h" #include "rsElement.h" // --------------------------------------------------------------------------- namespace android { namespace renderscript { -class ShaderCache; #define RS_SHADER_INTERNAL "//rs_shader_internal\n" #define RS_SHADER_ATTR "ATTRIB_" #define RS_SHADER_UNI "UNI_" -class Program : public ObjectBase { +class Program : public ProgramBase { public: - Program(Context *); Program(Context *, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength); virtual ~Program(); void bindAllocation(Context *, Allocation *, uint32_t slot); - virtual void createShader(); bool isUserProgram() const {return !mIsInternal;} void bindTexture(Context *, uint32_t slot, Allocation *); void bindSampler(Context *, uint32_t slot, Sampler *); - uint32_t getShaderID() const {return mShaderID;} - void setShader(const char *, uint32_t len); - - uint32_t getAttribCount() const {return mAttribCount;} - uint32_t getUniformCount() const {return mUniformCount;} - const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];} - const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];} - uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];} - - String8 getGLSLInputString() const; - String8 getGLSLOutputString() const; - String8 getGLSLConstantString() const; - - bool isValid() const {return mIsValid;} - void forceDirty() const {mDirty = true;} + struct Hal { + mutable void *drv; + + struct State { + // The difference between Textures and Constants is how they are accessed + // Texture lookups go though a sampler which in effect converts normalized + // coordinates into type specific. Multiple samples may also be taken + // and filtered. + // + // Constants are strictly accessed by the shader code + ObjectBaseRef<Allocation> *textures; + RsTextureTarget *textureTargets; + uint32_t texturesCount; + + ObjectBaseRef<Sampler> *samplers; + uint32_t samplersCount; + + ObjectBaseRef<Allocation> *constants; + ObjectBaseRef<Type> *constantTypes; + uint32_t constantsCount; + + ObjectBaseRef<Element> *inputElements; + uint32_t inputElementsCount; + }; + State state; + }; + Hal mHal; protected: - // Components not listed in "in" will be passed though - // unless overwritten by components in out. - ObjectBaseRef<Element> *mInputElements; - ObjectBaseRef<Element> *mOutputElements; - ObjectBaseRef<Type> *mConstantTypes; - ObjectBaseRef<Allocation> *mConstants; - uint32_t mInputCount; - uint32_t mOutputCount; - uint32_t mConstantCount; - bool mIsValid; bool mIsInternal; - - // Applies to vertex and fragment shaders only - void appendUserConstants(); - void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment); - void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); - - void initAttribAndUniformArray(); - - mutable bool mDirty; - String8 mShader; String8 mUserShader; - uint32_t mShaderID; - - uint32_t mTextureCount; - uint32_t mAttribCount; - uint32_t mUniformCount; - String8 *mAttribNames; - String8 *mUniformNames; - uint32_t *mUniformArraySizes; - - void logUniform(const Element *field, const float *fd, uint32_t arraySize ); - void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize ); void initMemberVars(); - - // The difference between Textures and Constants is how they are accessed - // Texture lookups go though a sampler which in effect converts normalized - // coordinates into type specific. Multiple samples may also be taken - // and filtered. - // - // Constants are strictly accessed by programetic loads. - ObjectBaseRef<Allocation> *mTextures; - ObjectBaseRef<Sampler> *mSamplers; - RsTextureTarget *mTextureTargets; - bool loadShader(Context *, uint32_t type); }; } } -#endif +#endif // ANDROID_RS_PROGRAM_H diff --git a/libs/rs/rsProgramBase.h b/libs/rs/rsProgramBase.h new file mode 100644 index 0000000..80da453 --- /dev/null +++ b/libs/rs/rsProgramBase.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef ANDROID_RS_PROGRAM_BASE_H +#define ANDROID_RS_PROGRAM_BASE_H + +#include "rsObjectBase.h" +#include "rsElement.h" + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class ProgramBase : public ObjectBase { +public: + ProgramBase(Context *rsc) : ObjectBase(rsc) { + mDirty = true; + } + + void forceDirty() const {mDirty = true;} + +protected: + mutable bool mDirty; +}; + +} +} +#endif // ANDROID_RS_PROGRAM_BASE_H + + + diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index ff314b7..356ff77 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -15,13 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramFragment.h" using namespace android; @@ -31,19 +24,16 @@ ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { - mConstantColor[0] = 1.f; mConstantColor[1] = 1.f; mConstantColor[2] = 1.f; mConstantColor[3] = 1.f; - init(rsc); + mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length()); } ProgramFragment::~ProgramFragment() { - if (mShaderID) { - mRSC->mShaderCache.cleanupFragment(mShaderID); - } + mRSC->mHal.funcs.fragment.destroy(mRSC, this); } void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) { @@ -52,7 +42,7 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set fixed function emulation color on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { LOGE("Unable to set fixed function emulation color because allocation is missing"); rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing"); return; @@ -61,107 +51,25 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, mConstantColor[1] = g; mConstantColor[2] = b; mConstantColor[3] = a; - memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float)); + memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float)); mDirty = true; } -void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) { - //LOGE("sgl2 frag1 %x", glGetError()); +void ProgramFragment::setup(Context *rsc, ProgramFragmentState *state) { if ((state->mLast.get() == this) && !mDirty) { return; } state->mLast.set(this); - rsc->checkError("ProgramFragment::setupGL2 start"); - - rsc->checkError("ProgramFragment::setupGL2 begin uniforms"); - setupUserConstants(rsc, sc, true); - - uint32_t numTexturesToBind = mTextureCount; - uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures(); - if (numTexturesToBind >= numTexturesAvailable) { - LOGE("Attempting to bind %u textures on shader id %u, but only %u are available", - mTextureCount, (uint32_t)this, numTexturesAvailable); - rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available"); - numTexturesToBind = numTexturesAvailable; - } - - for (uint32_t ct=0; ct < numTexturesToBind; ct++) { - glActiveTexture(GL_TEXTURE0 + ct); - if (!mTextures[ct].get()) { + for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) { + if (!mHal.state.textures[ct].get()) { LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct); rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound"); continue; } - - mTextures[ct]->uploadCheck(rsc); - GLenum target = (GLenum)mTextures[ct]->getGLTarget(); - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { - LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); - rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); - } - glBindTexture(target, mTextures[ct]->getTextureID()); - rsc->checkError("ProgramFragment::setupGL2 tex bind"); - if (mSamplers[ct].get()) { - mSamplers[ct]->setupGL(rsc, mTextures[ct].get()); - } else { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - rsc->checkError("ProgramFragment::setupGL2 tex env"); - } - - glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); - rsc->checkError("ProgramFragment::setupGL2 uniforms"); - } - - glActiveTexture(GL_TEXTURE0); - mDirty = false; - rsc->checkError("ProgramFragment::setupGL2"); -} - -void ProgramFragment::loadShader(Context *rsc) { - Program::loadShader(rsc, GL_FRAGMENT_SHADER); -} - -void ProgramFragment::createShader() { - if (mUserShader.length() > 1) { - mShader.append("precision mediump float;\n"); - appendUserConstants(); - char buf[256]; - for (uint32_t ct=0; ct < mTextureCount; ct++) { - if (mTextureTargets[ct] == RS_TEXTURE_2D) { - snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); - } else { - snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); - } - mShader.append(buf); - } - mShader.append(mUserShader); - } else { - LOGE("ProgramFragment::createShader cannot create program, shader code not defined"); - rsAssert(0); - } -} - -void ProgramFragment::init(Context *rsc) { - uint32_t uniformIndex = 0; - if (mUserShader.size() > 0) { - for (uint32_t ct=0; ct < mConstantCount; ct++) { - initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI); - } - } - mTextureUniformIndexStart = uniformIndex; - char buf[256]; - for (uint32_t ct=0; ct < mTextureCount; ct++) { - snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); - mUniformNames[uniformIndex].setTo(buf); - mUniformArraySizes[uniformIndex] = 1; - uniformIndex++; } - createShader(); + rsc->mHal.funcs.fragment.setActive(rsc, this); } void ProgramFragment::serialize(OStream *stream) const { @@ -200,7 +108,8 @@ void ProgramFragmentState::init(Context *rsc) { tmp[0] = RS_PROGRAM_PARAM_CONSTANT; tmp[1] = (uint32_t)inputType; - Allocation *constAlloc = new Allocation(rsc, inputType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); + Allocation *constAlloc = Allocation::createAllocation(rsc, inputType, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), shaderString.length(), tmp, 2); pf->bindAllocation(rsc, constAlloc, 0); @@ -218,8 +127,8 @@ namespace android { namespace renderscript { RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) { + size_t shaderLength, const uint32_t * params, + size_t paramLength) { ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength); pf->incUserRef(); //LOGE("rsi_ProgramFragmentCreate %p", pf); diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index 3d28946..d6e20cd 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -32,11 +32,8 @@ public: uint32_t paramLength); virtual ~ProgramFragment(); - virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc); + virtual void setup(Context *, ProgramFragmentState *); - virtual void createShader(); - virtual void loadShader(Context *rsc); - virtual void init(Context *rsc); virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; } static ProgramFragment *createFromStream(Context *rsc, IStream *stream); diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp index ace1572..435561d 100644 --- a/libs/rs/rsProgramRaster.cpp +++ b/libs/rs/rsProgramRaster.cpp @@ -15,11 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramRaster.h" using namespace android; @@ -27,49 +22,33 @@ using namespace android::renderscript; ProgramRaster::ProgramRaster(Context *rsc, bool pointSmooth, - bool lineSmooth, bool pointSprite) - : Program(rsc) { - - mPointSmooth = pointSmooth; - mLineSmooth = lineSmooth; - mPointSprite = pointSprite; - mLineWidth = 1.0f; - mCull = RS_CULL_BACK; -} + bool lineSmooth, bool pointSprite, + float lineWidth, RsCullMode cull) + : ProgramBase(rsc) { -ProgramRaster::~ProgramRaster() { -} + memset(&mHal, 0, sizeof(mHal)); + + mHal.state.pointSmooth = pointSmooth; + mHal.state.lineSmooth = lineSmooth; + mHal.state.pointSprite = pointSprite; + mHal.state.lineWidth = lineWidth; + mHal.state.cull = cull; -void ProgramRaster::setLineWidth(float s) { - mLineWidth = s; - mDirty = true; + rsc->mHal.funcs.raster.init(rsc, this); } -void ProgramRaster::setCullMode(RsCullMode mode) { - mCull = mode; - mDirty = true; +ProgramRaster::~ProgramRaster() { + mRSC->mHal.funcs.raster.destroy(mRSC, this); } -void ProgramRaster::setupGL2(const Context *rsc, ProgramRasterState *state) { +void ProgramRaster::setup(const Context *rsc, ProgramRasterState *state) { if (state->mLast.get() == this && !mDirty) { return; } state->mLast.set(this); mDirty = false; - switch (mCull) { - case RS_CULL_BACK: - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - break; - case RS_CULL_FRONT: - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - break; - case RS_CULL_NONE: - glDisable(GL_CULL_FACE); - break; - } + rsc->mHal.funcs.raster.setActive(rsc, this); } void ProgramRaster::serialize(OStream *stream) const { @@ -86,7 +65,7 @@ ProgramRasterState::~ProgramRasterState() { } void ProgramRasterState::init(Context *rsc) { - ProgramRaster *pr = new ProgramRaster(rsc, false, false, false); + ProgramRaster *pr = new ProgramRaster(rsc, false, false, false, 1.f, RS_CULL_BACK); mDefault.set(pr); } @@ -101,27 +80,15 @@ namespace renderscript { RsProgramRaster rsi_ProgramRasterCreate(Context * rsc, bool pointSmooth, bool lineSmooth, - bool pointSprite) { + bool pointSprite, + float lineWidth, + RsCullMode cull) { ProgramRaster *pr = new ProgramRaster(rsc, pointSmooth, - lineSmooth, pointSprite); + lineSmooth, pointSprite, lineWidth, cull); pr->incUserRef(); return pr; } -void rsi_ProgramRasterSetLineWidth(Context * rsc, - RsProgramRaster vpr, - float s) { - ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); - pr->setLineWidth(s); -} - -void rsi_ProgramRasterSetCullMode(Context * rsc, - RsProgramRaster vpr, - RsCullMode mode) { - ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); - pr->setCullMode(mode); -} - } } diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h index 7958af9..efdb948 100644 --- a/libs/rs/rsProgramRaster.h +++ b/libs/rs/rsProgramRaster.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-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. @@ -17,7 +17,7 @@ #ifndef ANDROID_RS_PROGRAM_RASTER_H #define ANDROID_RS_PROGRAM_RASTER_H -#include "rsProgram.h" +#include "rsProgramBase.h" // --------------------------------------------------------------------------- namespace android { @@ -25,28 +25,36 @@ namespace renderscript { class ProgramRasterState; -class ProgramRaster : public Program { +class ProgramRaster : public ProgramBase { public: ProgramRaster(Context *rsc, bool pointSmooth, bool lineSmooth, - bool pointSprite); + bool pointSprite, + float lineWidth, + RsCullMode cull); virtual ~ProgramRaster(); - virtual void setupGL2(const Context *, ProgramRasterState *); + virtual void setup(const Context *, ProgramRasterState *); virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; } static ProgramRaster *createFromStream(Context *rsc, IStream *stream); - void setLineWidth(float w); - void setCullMode(RsCullMode mode); + struct Hal { + mutable void *drv; + + struct State { + bool pointSmooth; + bool lineSmooth; + bool pointSprite; + float lineWidth; + RsCullMode cull; + }; + State state; + }; + Hal mHal; protected: - bool mPointSmooth; - bool mLineSmooth; - bool mPointSprite; - float mLineWidth; - RsCullMode mCull; }; class ProgramRasterState { diff --git a/libs/rs/rsProgramStore.cpp b/libs/rs/rsProgramStore.cpp index 09b759d..8fe890b 100644 --- a/libs/rs/rsProgramStore.cpp +++ b/libs/rs/rsProgramStore.cpp @@ -15,82 +15,43 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramStore.h" using namespace android; using namespace android::renderscript; -ProgramStore::ProgramStore(Context *rsc) : Program(rsc) { - mDitherEnable = true; - mBlendEnable = false; - mColorRWriteEnable = true; - mColorGWriteEnable = true; - mColorBWriteEnable = true; - mColorAWriteEnable = true; - mBlendSrc = GL_ONE; - mBlendDst = GL_ZERO; +ProgramStore::ProgramStore(Context *rsc, + bool colorMaskR, bool colorMaskG, bool colorMaskB, bool colorMaskA, + bool depthMask, bool ditherEnable, + RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc, + RsDepthFunc depthFunc) : ProgramBase(rsc) { + memset(&mHal, 0, sizeof(mHal)); + + mHal.state.ditherEnable = ditherEnable; + + mHal.state.colorRWriteEnable = colorMaskR; + mHal.state.colorGWriteEnable = colorMaskG; + mHal.state.colorBWriteEnable = colorMaskB; + mHal.state.colorAWriteEnable = colorMaskA; + mHal.state.blendSrc = srcFunc; + mHal.state.blendDst = destFunc; - mDepthTestEnable = false; - mDepthWriteEnable = true; - mDepthFunc = GL_LESS; + mHal.state.depthWriteEnable = depthMask; + mHal.state.depthFunc = depthFunc; } ProgramStore::~ProgramStore() { + mRSC->mHal.funcs.store.destroy(mRSC, this); } -void ProgramStore::setupGL2(const Context *rsc, ProgramStoreState *state) { +void ProgramStore::setup(const Context *rsc, ProgramStoreState *state) { if (state->mLast.get() == this) { return; } state->mLast.set(this); - glColorMask(mColorRWriteEnable, - mColorGWriteEnable, - mColorBWriteEnable, - mColorAWriteEnable); - if (mBlendEnable) { - glEnable(GL_BLEND); - glBlendFunc(mBlendSrc, mBlendDst); - } else { - glDisable(GL_BLEND); - } - - //LOGE("pfs %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc); - - if (rsc->mUserSurfaceConfig.depthMin > 0) { - glDepthMask(mDepthWriteEnable); - if (mDepthTestEnable || mDepthWriteEnable) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(mDepthFunc); - } else { - glDisable(GL_DEPTH_TEST); - } - } else { - glDepthMask(false); - glDisable(GL_DEPTH_TEST); - } - - if (rsc->mUserSurfaceConfig.stencilMin > 0) { - } else { - glStencilMask(0); - glDisable(GL_STENCIL_TEST); - } - - if (mDitherEnable) { - glEnable(GL_DITHER); - } else { - glDisable(GL_DITHER); - } -} - -void ProgramStore::setDitherEnable(bool enable) { - mDitherEnable = enable; + rsc->mHal.funcs.store.setActive(rsc, this); } void ProgramStore::serialize(OStream *stream) const { @@ -100,123 +61,24 @@ ProgramStore *ProgramStore::createFromStream(Context *rsc, IStream *stream) { return NULL; } -void ProgramStore::setDepthFunc(RsDepthFunc func) { - mDepthTestEnable = true; - - switch (func) { - case RS_DEPTH_FUNC_ALWAYS: - mDepthTestEnable = false; - mDepthFunc = GL_ALWAYS; - break; - case RS_DEPTH_FUNC_LESS: - mDepthFunc = GL_LESS; - break; - case RS_DEPTH_FUNC_LEQUAL: - mDepthFunc = GL_LEQUAL; - break; - case RS_DEPTH_FUNC_GREATER: - mDepthFunc = GL_GREATER; - break; - case RS_DEPTH_FUNC_GEQUAL: - mDepthFunc = GL_GEQUAL; - break; - case RS_DEPTH_FUNC_EQUAL: - mDepthFunc = GL_EQUAL; - break; - case RS_DEPTH_FUNC_NOTEQUAL: - mDepthFunc = GL_NOTEQUAL; - break; - } -} - -void ProgramStore::setDepthMask(bool mask) { - mDepthWriteEnable = mask; -} - -void ProgramStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst) { - mBlendEnable = true; - if ((src == RS_BLEND_SRC_ONE) && - (dst == RS_BLEND_DST_ZERO)) { - mBlendEnable = false; - } - - switch (src) { - case RS_BLEND_SRC_ZERO: - mBlendSrc = GL_ZERO; - break; - case RS_BLEND_SRC_ONE: - mBlendSrc = GL_ONE; - break; - case RS_BLEND_SRC_DST_COLOR: - mBlendSrc = GL_DST_COLOR; - break; - case RS_BLEND_SRC_ONE_MINUS_DST_COLOR: - mBlendSrc = GL_ONE_MINUS_DST_COLOR; - break; - case RS_BLEND_SRC_SRC_ALPHA: - mBlendSrc = GL_SRC_ALPHA; - break; - case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA: - mBlendSrc = GL_ONE_MINUS_SRC_ALPHA; - break; - case RS_BLEND_SRC_DST_ALPHA: - mBlendSrc = GL_DST_ALPHA; - break; - case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA: - mBlendSrc = GL_ONE_MINUS_DST_ALPHA; - break; - case RS_BLEND_SRC_SRC_ALPHA_SATURATE: - mBlendSrc = GL_SRC_ALPHA_SATURATE; - break; - } - - switch (dst) { - case RS_BLEND_DST_ZERO: - mBlendDst = GL_ZERO; - break; - case RS_BLEND_DST_ONE: - mBlendDst = GL_ONE; - break; - case RS_BLEND_DST_SRC_COLOR: - mBlendDst = GL_SRC_COLOR; - break; - case RS_BLEND_DST_ONE_MINUS_SRC_COLOR: - mBlendDst = GL_ONE_MINUS_SRC_COLOR; - break; - case RS_BLEND_DST_SRC_ALPHA: - mBlendDst = GL_SRC_ALPHA; - break; - case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA: - mBlendDst = GL_ONE_MINUS_SRC_ALPHA; - break; - case RS_BLEND_DST_DST_ALPHA: - mBlendDst = GL_DST_ALPHA; - break; - case RS_BLEND_DST_ONE_MINUS_DST_ALPHA: - mBlendDst = GL_ONE_MINUS_DST_ALPHA; - break; - } -} - -void ProgramStore::setColorMask(bool r, bool g, bool b, bool a) { - mColorRWriteEnable = r; - mColorGWriteEnable = g; - mColorBWriteEnable = b; - mColorAWriteEnable = a; +void ProgramStore::init() { + mRSC->mHal.funcs.store.init(mRSC, this); } ProgramStoreState::ProgramStoreState() { - mPFS = NULL; } ProgramStoreState::~ProgramStoreState() { - ObjectBase::checkDelete(mPFS); - mPFS = NULL; } void ProgramStoreState::init(Context *rsc) { - ProgramStore *pfs = new ProgramStore(rsc); - mDefault.set(pfs); + ProgramStore *ps = new ProgramStore(rsc, + true, true, true, true, + true, true, + RS_BLEND_SRC_ONE, RS_BLEND_DST_ZERO, + RS_DEPTH_FUNC_LESS); + ps->init(); + mDefault.set(ps); } void ProgramStoreState::deinit(Context *rsc) { @@ -224,40 +86,24 @@ void ProgramStoreState::deinit(Context *rsc) { mLast.clear(); } + namespace android { namespace renderscript { -void rsi_ProgramStoreBegin(Context * rsc, RsElement in, RsElement out) { - ObjectBase::checkDelete(rsc->mStateFragmentStore.mPFS); - rsc->mStateFragmentStore.mPFS = new ProgramStore(rsc); -} - -void rsi_ProgramStoreDepthFunc(Context *rsc, RsDepthFunc func) { - rsc->mStateFragmentStore.mPFS->setDepthFunc(func); -} - -void rsi_ProgramStoreDepthMask(Context *rsc, bool mask) { - rsc->mStateFragmentStore.mPFS->setDepthMask(mask); -} - -void rsi_ProgramStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a) { - rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a); -} - -void rsi_ProgramStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst) { - rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst); -} - -RsProgramStore rsi_ProgramStoreCreate(Context *rsc) { - ProgramStore *pfs = rsc->mStateFragmentStore.mPFS; +RsProgramStore rsi_ProgramStoreCreate(Context *rsc, + bool colorMaskR, bool colorMaskG, bool colorMaskB, bool colorMaskA, + bool depthMask, bool ditherEnable, + RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc, + RsDepthFunc depthFunc) { + + ProgramStore *pfs = new ProgramStore(rsc, + colorMaskR, colorMaskG, colorMaskB, colorMaskA, + depthMask, ditherEnable, + srcFunc, destFunc, depthFunc); + pfs->init(); pfs->incUserRef(); - rsc->mStateFragmentStore.mPFS = 0; return pfs; } -void rsi_ProgramStoreDither(Context *rsc, bool enable) { - rsc->mStateFragmentStore.mPFS->setDitherEnable(enable); -} - } } diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h index f8eb7cf..77b3881 100644 --- a/libs/rs/rsProgramStore.h +++ b/libs/rs/rsProgramStore.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -17,7 +17,7 @@ #ifndef ANDROID_RS_PROGRAM_FRAGMENT_STORE_H #define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H -#include "rsProgram.h" +#include "rsProgramBase.h" #include "rsStream.h" // --------------------------------------------------------------------------- @@ -26,41 +26,46 @@ namespace renderscript { class ProgramStoreState; -class ProgramStore : public Program { +class ProgramStore : public ProgramBase { public: - ProgramStore(Context *); + ProgramStore(Context *, + bool colorMaskR, bool colorMaskG, bool colorMaskB, bool colorMaskA, + bool depthMask, bool ditherEnable, + RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc, + RsDepthFunc depthFunc); virtual ~ProgramStore(); - virtual void setupGL2(const Context *, ProgramStoreState *); - - void setDepthFunc(RsDepthFunc); - void setDepthMask(bool); - - void setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst); - void setColorMask(bool, bool, bool, bool); - - void setDitherEnable(bool); + virtual void setup(const Context *, ProgramStoreState *); virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; } static ProgramStore *createFromStream(Context *rsc, IStream *stream); -protected: - bool mDitherEnable; + void init(); + + struct Hal { + mutable void *drv; - bool mBlendEnable; - bool mColorRWriteEnable; - bool mColorGWriteEnable; - bool mColorBWriteEnable; - bool mColorAWriteEnable; - int32_t mBlendSrc; - int32_t mBlendDst; + struct State { + bool ditherEnable; - bool mDepthTestEnable; - bool mDepthWriteEnable; - int32_t mDepthFunc; + //bool blendEnable; + bool colorRWriteEnable; + bool colorGWriteEnable; + bool colorBWriteEnable; + bool colorAWriteEnable; + RsBlendSrcFunc blendSrc; + RsBlendDstFunc blendDst; - bool mStencilTestEnable; + //bool depthTestEnable; + bool depthWriteEnable; + RsDepthFunc depthFunc; + }; + State state; + }; + Hal mHal; + +protected: }; class ProgramStoreState { @@ -72,9 +77,6 @@ public: ObjectBaseRef<ProgramStore> mDefault; ObjectBaseRef<ProgramStore> mLast; - - - ProgramStore *mPFS; }; } diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index 403c2a6..058a456 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -15,13 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsProgramVertex.h" using namespace android; @@ -32,73 +25,28 @@ ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { - init(rsc); + mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length()); } ProgramVertex::~ProgramVertex() { - if (mShaderID) { - mRSC->mShaderCache.cleanupVertex(mShaderID); - } -} - -void ProgramVertex::loadShader(Context *rsc) { - Program::loadShader(rsc, GL_VERTEX_SHADER); -} - -void ProgramVertex::createShader(Context *rsc) { - if (mUserShader.length() > 1) { - - appendUserConstants(); - - for (uint32_t ct=0; ct < mInputCount; ct++) { - const Element *e = mInputElements[ct].get(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } - - // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { - case 1: mShader.append("attribute float ATTRIB_"); break; - case 2: mShader.append("attribute vec2 ATTRIB_"); break; - case 3: mShader.append("attribute vec3 ATTRIB_"); break; - case 4: mShader.append("attribute vec4 ATTRIB_"); break; - default: - rsAssert(0); - } - - mShader.append(fn); - mShader.append(";\n"); - } - } - mShader.append(mUserShader); - } else { - rsc->setError(RS_ERROR_FATAL_UNKNOWN, - "ProgramFragment::createShader cannot create program, shader code not defined"); - } + mRSC->mHal.funcs.vertex.destroy(mRSC, this); } -void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) { +void ProgramVertex::setup(Context *rsc, ProgramVertexState *state) { if ((state->mLast.get() == this) && !mDirty) { return; } - rsc->checkError("ProgramVertex::setupGL2 start"); - if (!isUserProgram()) { - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrices because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); - Matrix mvp; + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); + Matrix4x4 mvp; mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); - Matrix t; + Matrix4x4 t; t.load(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]); mvp.multiply(&t); for (uint32_t i = 0; i < 16; i ++) { @@ -106,11 +54,9 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach } } - rsc->checkError("ProgramVertex::setupGL2 begin uniforms"); - setupUserConstants(rsc, sc, false); - state->mLast.set(this); - rsc->checkError("ProgramVertex::setupGL2"); + + rsc->mHal.funcs.vertex.setActive(rsc, this); } void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const { @@ -119,12 +65,12 @@ void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const "Attempting to set fixed function emulation matrix projection on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix projection because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -135,12 +81,12 @@ void ProgramVertex::setModelviewMatrix(Context *rsc, const rsc_Matrix *m) const "Attempting to set fixed function emulation matrix modelview on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix modelview because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -151,12 +97,12 @@ void ProgramVertex::setTextureMatrix(Context *rsc, const rsc_Matrix *m) const { "Attempting to set fixed function emulation matrix texture on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to set fixed function emulation matrix texture because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } @@ -167,12 +113,12 @@ void ProgramVertex::getProjectionMatrix(Context *rsc, rsc_Matrix *m) const { "Attempting to get fixed function emulation matrix projection on user program"); return; } - if (mConstants[0].get() == NULL) { + if (mHal.state.constants[0].get() == NULL) { rsc->setError(RS_ERROR_FATAL_UNKNOWN, "Unable to get fixed function emulation matrix projection because allocation is missing"); return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix)); } @@ -180,27 +126,13 @@ void ProgramVertex::transformToScreen(Context *rsc, float *v4out, const float *v if (isUserProgram()) { return; } - float *f = static_cast<float *>(mConstants[0]->getPtr()); - Matrix mvp; - mvp.loadMultiply((Matrix *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], - (Matrix *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); + float *f = static_cast<float *>(mHal.state.constants[0]->getPtr()); + Matrix4x4 mvp; + mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], + (Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); mvp.vectorMultiply(v4out, v3in); } -void ProgramVertex::init(Context *rsc) { - uint32_t attribCount = 0; - uint32_t uniformCount = 0; - if (mUserShader.size() > 0) { - for (uint32_t ct=0; ct < mInputCount; ct++) { - initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); - } - for (uint32_t ct=0; ct < mConstantCount; ct++) { - initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); - } - } - createShader(rsc); -} - void ProgramVertex::serialize(OStream *stream) const { } @@ -257,7 +189,8 @@ void ProgramVertexState::init(Context *rsc) { ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), shaderString.length(), tmp, 4); - Allocation *alloc = new Allocation(rsc, inputType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); + Allocation *alloc = Allocation::createAllocation(rsc, inputType, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); pv->bindAllocation(rsc, alloc, 0); mDefaultAlloc.set(alloc); @@ -269,7 +202,7 @@ void ProgramVertexState::init(Context *rsc) { void ProgramVertexState::updateSize(Context *rsc) { float *f = static_cast<float *>(mDefaultAlloc->getPtr()); - Matrix m; + Matrix4x4 m; m.loadOrtho(0,rsc->getWidth(), rsc->getHeight(),0, -1,1); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m.m, sizeof(m)); memcpy(&f[RS_PROGRAM_VERTEX_MVP_OFFSET], m.m, sizeof(m)); @@ -290,8 +223,8 @@ namespace android { namespace renderscript { RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) { + size_t shaderLength, const uint32_t * params, + size_t paramLength) { ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, params, paramLength); pv->incUserRef(); return pv; diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index 2a5c863..5cfdd8b 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -31,7 +31,7 @@ public: const uint32_t * params, uint32_t paramLength); virtual ~ProgramVertex(); - virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc); + virtual void setup(Context *rsc, ProgramVertexState *state); void setProjectionMatrix(Context *, const rsc_Matrix *) const; void getProjectionMatrix(Context *, rsc_Matrix *) const; @@ -40,10 +40,6 @@ public: void transformToScreen(Context *, float *v4out, const float *v3in) const; - virtual void createShader(Context *); - virtual void loadShader(Context *); - virtual void init(Context *); - virtual void serialize(OStream *stream) const; virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; } static ProgramVertex *createFromStream(Context *rsc, IStream *stream); diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h new file mode 100644 index 0000000..6d45285 --- /dev/null +++ b/libs/rs/rsRuntime.h @@ -0,0 +1,203 @@ +/* + * 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 "rsContext.h" +#include "rsScriptC.h" + +#include "utils/Timers.h" + +#include <time.h> + +namespace android { +namespace renderscript { + + +////////////////////////////////////////////////////////////////////////////// +// Context +////////////////////////////////////////////////////////////////////////////// + +void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *); +void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *); +void rsrBindProgramStore(Context *, Script *, ProgramStore *); +void rsrBindProgramFragment(Context *, Script *, ProgramFragment *); +void rsrBindProgramVertex(Context *, Script *, ProgramVertex *); +void rsrBindProgramRaster(Context *, Script *, ProgramRaster *); +void rsrBindFrameBufferObjectColorTarget(Context *, Script *, Allocation *, uint32_t slot); +void rsrBindFrameBufferObjectDepthTarget(Context *, Script *, Allocation *); +void rsrClearFrameBufferObjectColorTarget(Context *, Script *, uint32_t slot); +void rsrClearFrameBufferObjectDepthTarget(Context *, Script *); +void rsrClearFrameBufferObjectTargets(Context *, Script *); + +////////////////////////////////////////////////////////////////////////////// +// VP +////////////////////////////////////////////////////////////////////////////// + +void rsrVpLoadProjectionMatrix(Context *, Script *, const rsc_Matrix *m); +void rsrVpLoadModelMatrix(Context *, Script *, const rsc_Matrix *m); +void rsrVpLoadTextureMatrix(Context *, Script *, const rsc_Matrix *m); +void rsrPfConstantColor(Context *, Script *, ProgramFragment *, float r, float g, float b, float a); +void rsrVpGetProjectionMatrix(Context *, Script *, rsc_Matrix *m); + +////////////////////////////////////////////////////////////////////////////// +// Drawing +////////////////////////////////////////////////////////////////////////////// + +void rsrDrawQuadTexCoords(Context *, Script *, + float x1, float y1, float z1, float u1, float v1, + float x2, float y2, float z2, float u2, float v2, + float x3, float y3, float z3, float u3, float v3, + float x4, float y4, float z4, float u4, float v4); +void rsrDrawQuad(Context *, Script *, + float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4); +void rsrDrawSpriteScreenspace(Context *, Script *, + float x, float y, float z, float w, float h); +void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z); +void rsrDrawMesh(Context *, Script *, Mesh *); +void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex); +void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *, + uint32_t primIndex, uint32_t start, uint32_t len); +void rsrMeshComputeBoundingBox(Context *, Script *, Mesh *, + float *minX, float *minY, float *minZ, + float *maxX, float *maxY, float *maxZ); + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + + +void rsrColor(Context *, Script *, float r, float g, float b, float a); +void rsrFinish(Context *, Script *); +void rsrAllocationSyncAll(Context *, Script *, Allocation *); +void rsrClearColor(Context *, Script *, float r, float g, float b, float a); +void rsrClearDepth(Context *, Script *, float v); +uint32_t rsrGetWidth(Context *, Script *); +uint32_t rsrGetHeight(Context *, Script *); +void rsrDrawTextAlloc(Context *, Script *, Allocation *, int x, int y); +void rsrDrawText(Context *, Script *, const char *text, int x, int y); +void rsrSetMetrics(Context *, Script *, Font::Rect *metrics, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom); +void rsrMeasureTextAlloc(Context *, Script *, Allocation *, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom); +void rsrMeasureText(Context *, Script *, const char *text, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom); +void rsrBindFont(Context *, Script *, Font *); +void rsrFontColor(Context *, Script *, float r, float g, float b, float a); + +////////////////////////////////////////////////////////////////////////////// +// Time routines +////////////////////////////////////////////////////////////////////////////// + +float rsrGetDt(Context *, Script *); +time_t rsrTime(Context *, Script *, time_t *timer); +tm* rsrLocalTime(Context *, Script *, tm *local, time_t *timer); +int64_t rsrUptimeMillis(Context *, Script *); +int64_t rsrUptimeNanos(Context *, Script *); + +////////////////////////////////////////////////////////////////////////////// +// Message routines +////////////////////////////////////////////////////////////////////////////// + +uint32_t rsrToClient(Context *, Script *, int cmdID, void *data, int len); +uint32_t rsrToClientBlocking(Context *, Script *, int cmdID, void *data, int len); + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + +void rsrSetObject(const Context *, const Script *, ObjectBase **dst, ObjectBase * src); +void rsrClearObject(const Context *, const Script *, ObjectBase **dst); +bool rsrIsObject(const Context *, const Script *, const ObjectBase *src); + +void rsrAllocationIncRefs(const Context *, const Allocation *, void *ptr, + size_t elementCount, size_t startOffset); +void rsrAllocationDecRefs(const Context *, const Allocation *, void *ptr, + size_t elementCount, size_t startOffset); + + +uint32_t rsrToClient(Context *, Script *, int cmdID, void *data, int len); +uint32_t rsrToClientBlocking(Context *, Script *, int cmdID, void *data, int len); +const Allocation * rsrGetAllocation(Context *, Script *, const void *ptr); + +void rsrAllocationMarkDirty(Context *, Script *, RsAllocation a); +void rsrAllocationSyncAll(Context *, Script *, Allocation *a, RsAllocationUsageType source); + + +void rsrForEach(Context *, Script *, Script *target, + Allocation *in, + Allocation *out, + const void *usr, + uint32_t usrBytes, + const RsScriptCall *call); + + +////////////////////////////////////////////////////////////////////////////// +// Heavy math functions +////////////////////////////////////////////////////////////////////////////// + + +void rsrMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v); +float rsrMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col); +void rsrMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v); +float rsrMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col); +void rsrMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v); +float rsrMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col); +void rsrMatrixLoadIdentity_4x4(rs_matrix4x4 *m); +void rsrMatrixLoadIdentity_3x3(rs_matrix3x3 *m); +void rsrMatrixLoadIdentity_2x2(rs_matrix2x2 *m); +void rsrMatrixLoad_4x4_f(rs_matrix4x4 *m, const float *v); +void rsrMatrixLoad_3x3_f(rs_matrix3x3 *m, const float *v); +void rsrMatrixLoad_2x2_f(rs_matrix2x2 *m, const float *v); +void rsrMatrixLoad_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *v); +void rsrMatrixLoad_4x4_3x3(rs_matrix4x4 *m, const rs_matrix3x3 *v); +void rsrMatrixLoad_4x4_2x2(rs_matrix4x4 *m, const rs_matrix2x2 *v); +void rsrMatrixLoad_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *v); +void rsrMatrixLoad_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *v); +void rsrMatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z); +void rsrMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z); +void rsrMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z); +void rsrMatrixLoadMultiply_4x4_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, + const rs_matrix4x4 *rhs); +void rsrMatrixMultiply_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *rhs); +void rsrMatrixLoadMultiply_3x3_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, + const rs_matrix3x3 *rhs); +void rsrMatrixMultiply_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *rhs); +void rsrMatrixLoadMultiply_2x2_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, + const rs_matrix2x2 *rhs); +void rsrMatrixMultiply_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *rhs); +void rsrMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z); +void rsrMatrixScale(rs_matrix4x4 *m, float x, float y, float z); +void rsrMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z); +void rsrMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, + float bottom, float top, float near, float far); +void rsrMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, + float bottom, float top, float near, float far); +void rsrMatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far); + +// Returns true if the matrix was successfully inversed +bool rsrMatrixInverse_4x4(rs_matrix4x4 *m); +// Returns true if the matrix was successfully inversed +bool rsrMatrixInverseTranspose_4x4(rs_matrix4x4 *m); + +void rsrMatrixTranspose_4x4(rs_matrix4x4 *m); +void rsrMatrixTranspose_3x3(rs_matrix3x3 *m); +void rsrMatrixTranspose_2x2(rs_matrix2x2 *m); + +} +} diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp index db2383a..2a05d16 100644 --- a/libs/rs/rsSampler.cpp +++ b/libs/rs/rsSampler.cpp @@ -15,11 +15,6 @@ */ #include "rsContext.h" -#ifndef ANDROID_RS_SERIALIZE -#include <GLES/gl.h> -#include <GLES/glext.h> -#endif //ANDROID_RS_SERIALIZE - #include "rsSampler.h" @@ -39,77 +34,18 @@ Sampler::Sampler(Context *rsc, RsSamplerValue wrapT, RsSamplerValue wrapR, float aniso) : ObjectBase(rsc) { - mMagFilter = magFilter; - mMinFilter = minFilter; - mWrapS = wrapS; - mWrapT = wrapT; - mWrapR = wrapR; - mAniso = aniso; + mHal.state.magFilter = magFilter; + mHal.state.minFilter = minFilter; + mHal.state.wrapS = wrapS; + mHal.state.wrapT = wrapT; + mHal.state.wrapR = wrapR; + mHal.state.aniso = aniso; + + mRSC->mHal.funcs.sampler.init(mRSC, this); } Sampler::~Sampler() { -} - -void Sampler::setupGL(const Context *rsc, const Allocation *tex) { - GLenum trans[] = { - GL_NEAREST, //RS_SAMPLER_NEAREST, - GL_LINEAR, //RS_SAMPLER_LINEAR, - GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, - GL_REPEAT, //RS_SAMPLER_WRAP, - GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP - GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST - }; - - GLenum transNP[] = { - GL_NEAREST, //RS_SAMPLER_NEAREST, - GL_LINEAR, //RS_SAMPLER_LINEAR, - GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, - GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP, - GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP - GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST, - }; - - // This tells us the correct texture type - GLenum target = (GLenum)tex->getGLTarget(); - - if (!rsc->ext_OES_texture_npot() && tex->getType()->getIsNp2()) { - if (tex->getHasGraphicsMipmaps() && - (rsc->ext_GL_NV_texture_npot_2D_mipmap() || rsc->ext_GL_IMG_texture_npot())) { - if (rsc->ext_GL_NV_texture_npot_2D_mipmap()) { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); - } else { - switch (trans[mMinFilter]) { - case GL_LINEAR_MIPMAP_LINEAR: - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - break; - default: - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); - break; - } - } - } else { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); - } - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]); - glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[mWrapS]); - glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[mWrapT]); - } else { - if (tex->getHasGraphicsMipmaps()) { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); - } else { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); - } - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]); - glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[mWrapS]); - glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[mWrapT]); - } - - float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mAniso); - if (rsc->ext_texture_max_aniso() > 1.0f) { - glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); - } - - rsc->checkError("Sampler::setupGL2 tex env"); + mRSC->mHal.funcs.sampler.destroy(mRSC, this); } void Sampler::bindToContext(SamplerState *ss, uint32_t slot) { @@ -135,66 +71,14 @@ Sampler *Sampler::createFromStream(Context *rsc, IStream *stream) { namespace android { namespace renderscript { - -void rsi_SamplerBegin(Context *rsc) { - SamplerState * ss = &rsc->mStateSampler; - - ss->mMagFilter = RS_SAMPLER_LINEAR; - ss->mMinFilter = RS_SAMPLER_LINEAR; - ss->mWrapS = RS_SAMPLER_WRAP; - ss->mWrapT = RS_SAMPLER_WRAP; - ss->mWrapR = RS_SAMPLER_WRAP; - ss->mAniso = 1.0f; -} - -void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value) { - SamplerState * ss = &rsc->mStateSampler; - - switch (param) { - case RS_SAMPLER_MAG_FILTER: - ss->mMagFilter = value; - break; - case RS_SAMPLER_MIN_FILTER: - ss->mMinFilter = value; - break; - case RS_SAMPLER_WRAP_S: - ss->mWrapS = value; - break; - case RS_SAMPLER_WRAP_T: - ss->mWrapT = value; - break; - case RS_SAMPLER_WRAP_R: - ss->mWrapR = value; - break; - default: - LOGE("Attempting to set invalid value on sampler"); - break; - } -} - -void rsi_SamplerSet2(Context *rsc, RsSamplerParam param, float value) { - SamplerState * ss = &rsc->mStateSampler; - - switch (param) { - case RS_SAMPLER_ANISO: - ss->mAniso = value; - break; - default: - LOGE("Attempting to set invalid value on sampler"); - break; - } -} - -RsSampler rsi_SamplerCreate(Context *rsc) { - SamplerState * ss = &rsc->mStateSampler; - - Sampler * s = new Sampler(rsc, - ss->mMagFilter, - ss->mMinFilter, - ss->mWrapS, - ss->mWrapT, - ss->mWrapR, - ss->mAniso); +RsSampler rsi_SamplerCreate(Context * rsc, + RsSamplerValue magFilter, + RsSamplerValue minFilter, + RsSamplerValue wrapS, + RsSamplerValue wrapT, + RsSamplerValue wrapR, + float aniso) { + Sampler * s = new Sampler(rsc, magFilter, minFilter, wrapS, wrapT, wrapR, aniso); s->incUserRef(); return s; } diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h index 737bb8b..90b6082 100644 --- a/libs/rs/rsSampler.h +++ b/libs/rs/rsSampler.h @@ -40,9 +40,6 @@ public: virtual ~Sampler(); - void bind(Allocation *); - void setupGL(const Context *, const Allocation *); - void bindToContext(SamplerState *, uint32_t slot); void unbindFromContext(SamplerState *); @@ -50,14 +47,22 @@ public: virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; } static Sampler *createFromStream(Context *rsc, IStream *stream); -protected: - RsSamplerValue mMagFilter; - RsSamplerValue mMinFilter; - RsSamplerValue mWrapS; - RsSamplerValue mWrapT; - RsSamplerValue mWrapR; - float mAniso; + struct Hal { + mutable void *drv; + + struct State { + RsSamplerValue magFilter; + RsSamplerValue minFilter; + RsSamplerValue wrapS; + RsSamplerValue wrapT; + RsSamplerValue wrapR; + float aniso; + }; + State state; + }; + Hal mHal; +protected: int32_t mBoundSlot; private: @@ -67,13 +72,6 @@ private: class SamplerState { public: - RsSamplerValue mMagFilter; - RsSamplerValue mMinFilter; - RsSamplerValue mWrapS; - RsSamplerValue mWrapT; - RsSamplerValue mWrapR; - float mAniso; - ObjectBaseRef<Sampler> mSamplers[RS_MAX_SAMPLER_SLOT]; }; diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index afee2a3..f62c72e 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -21,6 +21,7 @@ using namespace android::renderscript; Script::Script(Context *rsc) : ObjectBase(rsc) { memset(&mEnviroment, 0, sizeof(mEnviroment)); + memset(&mHal, 0, sizeof(mHal)); mSlots = NULL; mTypes = NULL; @@ -37,48 +38,38 @@ Script::~Script() { } } -void Script::initSlots() { - if (mEnviroment.mFieldCount > 0) { - mSlots = new ObjectBaseRef<Allocation>[mEnviroment.mFieldCount]; - mTypes = new ObjectBaseRef<const Type>[mEnviroment.mFieldCount]; - } -} - void Script::setSlot(uint32_t slot, Allocation *a) { - if (slot >= mEnviroment.mFieldCount) { + //LOGE("setSlot %i %p", slot, a); + if (slot >= mHal.info.exportedVariableCount) { LOGE("Script::setSlot unable to set allocation, invalid slot index"); return; } mSlots[slot].set(a); + if (a != NULL) { + mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, a->getPtr()); + } else { + mRSC->mHal.funcs.script.setGlobalBind(mRSC, this, slot, NULL); + } } -void Script::setVar(uint32_t slot, const void *val, uint32_t len) { - int32_t *destPtr = ((int32_t **)mEnviroment.mFieldAddress)[slot]; - if (destPtr) { - //LOGE("setVar f1 %f", ((const float *)destPtr)[0]); - //LOGE("setVar %p %i", destPtr, len); - memcpy(destPtr, val, len); - //LOGE("setVar f2 %f", ((const float *)destPtr)[0]); - } else { - //if (rsc->props.mLogScripts) { - LOGV("Calling setVar on slot = %i which is null", slot); - //} +void Script::setVar(uint32_t slot, const void *val, size_t len) { + //LOGE("setVar %i %p %i", slot, val, len); + if (slot >= mHal.info.exportedVariableCount) { + LOGE("Script::setVar unable to set allocation, invalid slot index"); + return; } + mRSC->mHal.funcs.script.setGlobalVar(mRSC, this, slot, (void *)val, len); } void Script::setVarObj(uint32_t slot, ObjectBase *val) { - ObjectBase **destPtr = ((ObjectBase ***)mEnviroment.mFieldAddress)[slot]; - - if (destPtr) { - if (val != NULL) { - val->incSysRef(); - } - if (*destPtr) { - (*destPtr)->decSysRef(); - } - *destPtr = val; + //LOGE("setVarObj %i %p", slot, val); + if (slot >= mHal.info.exportedVariableCount) { + LOGE("Script::setVarObj unable to set allocation, invalid slot index"); + return; } + //LOGE("setvarobj %i %p", slot, val); + mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val); } namespace android { @@ -91,11 +82,21 @@ void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint3 //LOGE("rsi_ScriptBindAllocation %i %p %p", slot, a, a->getPtr()); } -void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length) { +void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, size_t length) { Script *s = static_cast<Script *>(vs); s->mEnviroment.mTimeZone = timeZone; } +void rsi_ScriptForEach(Context *rsc, RsScript vs, uint32_t slot, + RsAllocation vain, RsAllocation vaout, + const void *params, size_t paramLen) { + Script *s = static_cast<Script *>(vs); + s->runForEach(rsc, + static_cast<const Allocation *>(vain), static_cast<Allocation *>(vaout), + params, paramLen); + +} + void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot) { Script *s = static_cast<Script *>(vs); s->Invoke(rsc, slot, NULL, 0); @@ -107,7 +108,7 @@ void rsi_ScriptInvokeData(Context *rsc, RsScript vs, uint32_t slot, void *data) s->Invoke(rsc, slot, NULL, 0); } -void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { +void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, size_t len) { Script *s = static_cast<Script *>(vs); s->Invoke(rsc, slot, data, len); } @@ -138,7 +139,7 @@ void rsi_ScriptSetVarD(Context *rsc, RsScript vs, uint32_t slot, double value) { s->setVar(slot, &value, sizeof(value)); } -void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { +void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, size_t len) { Script *s = static_cast<Script *>(vs); s->setVar(slot, data, len); } diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index bad095b..c0324dd 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -31,6 +31,26 @@ class ProgramStore; class Script : public ObjectBase { public: + struct Hal { + void * drv; + + struct DriverInfo { + int mVersionMajor; + int mVersionMinor; + + size_t exportedVariableCount; + size_t exportedFunctionCount; + size_t exportedPragmaCount; + char const **exportedPragmaKeyList; + char const **exportedPragmaValueList; + + int (* root)(); + bool isThreadable; + }; + DriverInfo info; + }; + Hal mHal; + typedef void (* InvokeFunc_t)(void); Script(Context *); @@ -45,31 +65,22 @@ public: ObjectBaseRef<ProgramFragment> mFragment; ObjectBaseRef<ProgramRaster> mRaster; ObjectBaseRef<ProgramStore> mFragmentStore; - - uint32_t mInvokeFunctionCount; - InvokeFunc_t *mInvokeFunctions; - uint32_t mFieldCount; - void ** mFieldAddress; - - char * mScriptText; - uint32_t mScriptTextLength; - - bool mIsThreadable; }; Enviroment_t mEnviroment; void initSlots(); void setSlot(uint32_t slot, Allocation *a); - void setVar(uint32_t slot, const void *val, uint32_t len); + void setVar(uint32_t slot, const void *val, size_t len); void setVarObj(uint32_t slot, ObjectBase *val); virtual void runForEach(Context *rsc, const Allocation * ain, Allocation * aout, const void * usr, + size_t usrBytes, const RsScriptCall *sc = NULL) = 0; - virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0; + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) = 0; virtual void setupScript(Context *rsc) = 0; virtual uint32_t run(Context *) = 0; protected: diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index e12926b..b230bb5 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -16,17 +16,8 @@ #include "rsContext.h" #include "rsScriptC.h" -#include "rsMatrix.h" #include "utils/Timers.h" #include "utils/StopWatch.h" -extern "C" { -#include "libdex/ZipArchive.h" -} - -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include <bcc/bcc.h> using namespace android; using namespace android::renderscript; @@ -36,94 +27,18 @@ using namespace android::renderscript; Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript -// Input: cacheDir -// Input: resName -// Input: extName -// -// Note: cacheFile = resName + extName -// -// Output: Returns cachePath == cacheDir + cacheFile -char *genCacheFileName(const char *cacheDir, - const char *resName, - const char *extName) { - char cachePath[512]; - char cacheFile[sizeof(cachePath)]; - const size_t kBufLen = sizeof(cachePath) - 1; - - cacheFile[0] = '\0'; - // Note: resName today is usually something like - // "/com.android.fountain:raw/fountain" - if (resName[0] != '/') { - // Get the absolute path of the raw/***.bc file. - - // Generate the absolute path. This doesn't do everything it - // should, e.g. if resName is "./out/whatever" it doesn't crunch - // the leading "./" out because this if-block is not triggered, - // but it'll make do. - // - if (getcwd(cacheFile, kBufLen) == NULL) { - LOGE("Can't get CWD while opening raw/***.bc file\n"); - return NULL; - } - // Append "/" at the end of cacheFile so far. - strncat(cacheFile, "/", kBufLen); - } - - // cacheFile = resName + extName - // - strncat(cacheFile, resName, kBufLen); - if (extName != NULL) { - // TODO(srhines): strncat() is a bit dangerous - strncat(cacheFile, extName, kBufLen); - } - - // Turn the path into a flat filename by replacing - // any slashes after the first one with '@' characters. - char *cp = cacheFile + 1; - while (*cp != '\0') { - if (*cp == '/') { - *cp = '@'; - } - cp++; - } - - // Tack on the file name for the actual cache file path. - strncpy(cachePath, cacheDir, kBufLen); - strncat(cachePath, cacheFile, kBufLen); - - LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath); - return strdup(cachePath); -} - ScriptC::ScriptC(Context *rsc) : Script(rsc) { - mBccScript = NULL; - memset(&mProgram, 0, sizeof(mProgram)); } ScriptC::~ScriptC() { - if (mBccScript) { - if (mProgram.mObjectSlotList) { - for (size_t ct=0; ct < mProgram.mObjectSlotCount; ct++) { - setVarObj(mProgram.mObjectSlotList[ct], NULL); - } - delete [] mProgram.mObjectSlotList; - mProgram.mObjectSlotList = NULL; - mProgram.mObjectSlotCount = 0; - } - - - LOGD(">>>> ~ScriptC bccDisposeScript(%p)", mBccScript); - bccDisposeScript(mBccScript); - } - free(mEnviroment.mScriptText); - mEnviroment.mScriptText = NULL; + mRSC->mHal.funcs.script.destroy(mRSC, this); } void ScriptC::setupScript(Context *rsc) { mEnviroment.mStartTimeMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); - for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { if (mSlots[ct].get() && !mTypes[ct].get()) { mTypes[ct].set(mSlots[ct]->getType()); } @@ -134,27 +49,17 @@ void ScriptC::setupScript(Context *rsc) { if (mSlots[ct].get()) { ptr = mSlots[ct]->getPtr(); } - void **dest = ((void ***)mEnviroment.mFieldAddress)[ct]; - if (rsc->props.mLogScripts) { - if (mSlots[ct].get() != NULL) { - LOGV("%p ScriptC::setupScript slot=%i dst=%p src=%p type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType()); - } else { - LOGV("%p ScriptC::setupScript slot=%i dst=%p src=%p type=null", rsc, ct, dest, ptr); - } - } - - if (dest) { - *dest = ptr; - } + rsc->mHal.funcs.script.setGlobalBind(rsc, this, ct, ptr); } } const Allocation *ScriptC::ptrToAllocation(const void *ptr) const { + //LOGE("ptr to alloc %p", ptr); if (!ptr) { return NULL; } - for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + for (uint32_t ct=0; ct < mHal.info.exportedVariableCount; ct++) { if (!mSlots[ct].get()) continue; if (mSlots[ct]->getPtr() == ptr) { @@ -165,15 +70,6 @@ const Allocation *ScriptC::ptrToAllocation(const void *ptr) const { return NULL; } -Script * ScriptC::setTLS(Script *sc) { - Context::ScriptTLSStruct * tls = (Context::ScriptTLSStruct *) - pthread_getspecific(Context::gThreadTLSKey); - rsAssert(tls); - Script *old = tls->mScript; - tls->mScript = sc; - return old; -} - void ScriptC::setupGLState(Context *rsc) { if (mEnviroment.mFragmentStore.get()) { rsc->setProgramStore(mEnviroment.mFragmentStore.get()); @@ -190,7 +86,7 @@ void ScriptC::setupGLState(Context *rsc) { } uint32_t ScriptC::run(Context *rsc) { - if (mProgram.mRoot == NULL) { + if (mHal.info.root == NULL) { rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); return 0; } @@ -199,235 +95,46 @@ uint32_t ScriptC::run(Context *rsc) { setupScript(rsc); uint32_t ret = 0; - Script * oldTLS = setTLS(this); if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::run invoking root, ptr %p", rsc, mProgram.mRoot); + LOGV("%p ScriptC::run invoking root, ptr %p", rsc, mHal.info.root); } - ret = mProgram.mRoot(); + ret = rsc->mHal.funcs.script.invokeRoot(rsc, this); if (rsc->props.mLogScripts) { LOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); } - setTLS(oldTLS); return ret; } -typedef struct { - Context *rsc; - ScriptC *script; - const Allocation * ain; - Allocation * aout; - const void * usr; - - uint32_t mSliceSize; - volatile int mSliceNum; - - const uint8_t *ptrIn; - uint32_t eStrideIn; - uint8_t *ptrOut; - uint32_t eStrideOut; - - uint32_t xStart; - uint32_t xEnd; - uint32_t yStart; - uint32_t yEnd; - uint32_t zStart; - uint32_t zEnd; - uint32_t arrayStart; - uint32_t arrayEnd; - - uint32_t dimX; - uint32_t dimY; - uint32_t dimZ; - uint32_t dimArray; -} MTLaunchStruct; -typedef int (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t); - -static void wc_xy(void *usr, uint32_t idx) { - MTLaunchStruct *mtls = (MTLaunchStruct *)usr; - - while (1) { - uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); - uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize; - uint32_t yEnd = yStart + mtls->mSliceSize; - yEnd = rsMin(yEnd, mtls->yEnd); - if (yEnd <= yStart) { - return; - } - - //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); - //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); - for (uint32_t y = yStart; y < yEnd; y++) { - uint32_t offset = mtls->dimX * y; - uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset); - const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset); - - for (uint32_t x = mtls->xStart; x < mtls->xEnd; x++) { - ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, y, 0, 0); - xPtrIn += mtls->eStrideIn; - xPtrOut += mtls->eStrideOut; - } - } - } -} - -static void wc_x(void *usr, uint32_t idx) { - MTLaunchStruct *mtls = (MTLaunchStruct *)usr; - - while (1) { - uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum); - uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize; - uint32_t xEnd = xStart + mtls->mSliceSize; - xEnd = rsMin(xEnd, mtls->xEnd); - if (xEnd <= xStart) { - return; - } - - //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd); - //LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut); - uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart); - const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart); - for (uint32_t x = xStart; x < xEnd; x++) { - ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0); - xPtrIn += mtls->eStrideIn; - xPtrOut += mtls->eStrideOut; - } - } -} void ScriptC::runForEach(Context *rsc, const Allocation * ain, Allocation * aout, const void * usr, + size_t usrBytes, const RsScriptCall *sc) { - MTLaunchStruct mtls; - memset(&mtls, 0, sizeof(mtls)); - Context::PushState ps(rsc); - if (ain) { - mtls.dimX = ain->getType()->getDimX(); - mtls.dimY = ain->getType()->getDimY(); - mtls.dimZ = ain->getType()->getDimZ(); - //mtls.dimArray = ain->getType()->getDimArray(); - } else if (aout) { - mtls.dimX = aout->getType()->getDimX(); - mtls.dimY = aout->getType()->getDimY(); - mtls.dimZ = aout->getType()->getDimZ(); - //mtls.dimArray = aout->getType()->getDimArray(); - } else { - rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations"); - return; - } - - if (!sc || (sc->xEnd == 0)) { - mtls.xEnd = mtls.dimX; - } else { - rsAssert(sc->xStart < mtls.dimX); - rsAssert(sc->xEnd <= mtls.dimX); - rsAssert(sc->xStart < sc->xEnd); - mtls.xStart = rsMin(mtls.dimX, sc->xStart); - mtls.xEnd = rsMin(mtls.dimX, sc->xEnd); - if (mtls.xStart >= mtls.xEnd) return; - } - - if (!sc || (sc->yEnd == 0)) { - mtls.yEnd = mtls.dimY; - } else { - rsAssert(sc->yStart < mtls.dimY); - rsAssert(sc->yEnd <= mtls.dimY); - rsAssert(sc->yStart < sc->yEnd); - mtls.yStart = rsMin(mtls.dimY, sc->yStart); - mtls.yEnd = rsMin(mtls.dimY, sc->yEnd); - if (mtls.yStart >= mtls.yEnd) return; - } - - mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd); - mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd); - mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd); - mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd); - - rsAssert(ain->getType()->getDimZ() == 0); + Context::PushState ps(rsc); setupGLState(rsc); setupScript(rsc); - Script * oldTLS = setTLS(this); - - mtls.rsc = rsc; - mtls.ain = ain; - mtls.aout = aout; - mtls.script = this; - mtls.usr = usr; - mtls.mSliceSize = 10; - mtls.mSliceNum = 0; - - mtls.ptrIn = NULL; - mtls.eStrideIn = 0; - if (ain) { - mtls.ptrIn = (const uint8_t *)ain->getPtr(); - mtls.eStrideIn = ain->getType()->getElementSizeBytes(); - } - - mtls.ptrOut = NULL; - mtls.eStrideOut = 0; - if (aout) { - mtls.ptrOut = (uint8_t *)aout->getPtr(); - mtls.eStrideOut = aout->getType()->getElementSizeBytes(); - } - - if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable) { - if (mtls.dimY > 1) { - rsc->launchThreads(wc_xy, &mtls); - } else { - rsc->launchThreads(wc_x, &mtls); - } - - //LOGE("launch 1"); - } else { - //LOGE("launch 3"); - for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) { - for (uint32_t z = mtls.zStart; z < mtls.zEnd; z++) { - for (uint32_t y = mtls.yStart; y < mtls.yEnd; y++) { - uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * ar + - mtls.dimX * mtls.dimY * z + - mtls.dimX * y; - uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset); - const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset); - - for (uint32_t x = mtls.xStart; x < mtls.xEnd; x++) { - ((rs_t)mProgram.mRoot) (xPtrIn, xPtrOut, usr, x, y, z, ar); - xPtrIn += mtls.eStrideIn; - xPtrOut += mtls.eStrideOut; - } - } - } - } - } - - setTLS(oldTLS); + rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, usrBytes, sc); } -void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) { - if ((slot >= mEnviroment.mInvokeFunctionCount) || - (mEnviroment.mInvokeFunctions[slot] == NULL)) { +void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) { + if (slot >= mHal.info.exportedFunctionCount) { rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); return; } setupScript(rsc); - Script * oldTLS = setTLS(this); if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, mEnviroment.mInvokeFunctions[slot]); - } - ((void (*)(const void *, uint32_t)) - mEnviroment.mInvokeFunctions[slot])(data, len); - if (rsc->props.mLogScripts) { - LOGV("%p ScriptC::Invoke complete", rsc); + LOGV("%p ScriptC::Invoke invoking slot %i, ptr %p", rsc, slot, this); } - - setTLS(oldTLS); + rsc->mHal.funcs.script.invokeFunction(rsc, this, slot, data, len); } ScriptCState::ScriptCState() { @@ -436,13 +143,14 @@ ScriptCState::ScriptCState() { ScriptCState::~ScriptCState() { } +/* static void* symbolLookup(void* pContext, char const* name) { const ScriptCState::SymbolTable_t *sym; ScriptC *s = (ScriptC *)pContext; if (!strcmp(name, "__isThreadable")) { - return (void*) s->mEnviroment.mIsThreadable; + return (void*) s->mHal.info.isThreadable; } else if (!strcmp(name, "__clearThreadable")) { - s->mEnviroment.mIsThreadable = false; + s->mHal.info.isThreadable = false; return NULL; } sym = ScriptCState::lookupSymbol(name); @@ -453,156 +161,99 @@ static void* symbolLookup(void* pContext, char const* name) { sym = ScriptCState::lookupSymbolGL(name); } if (sym) { - s->mEnviroment.mIsThreadable &= sym->threadable; + s->mHal.info.isThreadable &= sym->threadable; return sym->mPtr; } LOGE("ScriptC sym lookup failed for %s", name); return NULL; } +*/ #if 0 extern const char rs_runtime_lib_bc[]; extern unsigned rs_runtime_lib_bc_size; #endif -bool ScriptCState::runCompiler(Context *rsc, - ScriptC *s, - const char *resName, - const char *cacheDir) { - s->mBccScript = bccCreateScript(); - - s->mEnviroment.mIsThreadable = true; - - if (bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s) != 0) { - LOGE("bcc: FAILS to register symbol callback"); - return false; - } - - if (bccReadBC(s->mBccScript, - resName, - s->mEnviroment.mScriptText, - s->mEnviroment.mScriptTextLength, 0) != 0) { - LOGE("bcc: FAILS to read bitcode"); - return false; - } - -#if 1 - if (bccLinkFile(s->mBccScript, "/system/lib/libclcore.bc", 0) != 0) { - LOGE("bcc: FAILS to link bitcode"); - return false; - } -#endif - char *cachePath = genCacheFileName(cacheDir, resName, ".oBCC"); - - if (bccPrepareExecutable(s->mBccScript, cachePath, 0) != 0) { - LOGE("bcc: FAILS to prepare executable"); - return false; - } - - free(cachePath); +bool ScriptC::runCompiler(Context *rsc, + const char *resName, + const char *cacheDir, + const uint8_t *bitcode, + size_t bitcodeLen) { - s->mProgram.mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(s->mBccScript, "root")); - s->mProgram.mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(s->mBccScript, "init")); + //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); - if (s->mProgram.mInit) { - s->mProgram.mInit(); - } - - s->mEnviroment.mInvokeFunctionCount = bccGetExportFuncCount(s->mBccScript); - if (s->mEnviroment.mInvokeFunctionCount <= 0) - s->mEnviroment.mInvokeFunctions = NULL; - else { - s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t)); - bccGetExportFuncList(s->mBccScript, s->mEnviroment.mInvokeFunctionCount, (void **) s->mEnviroment.mInvokeFunctions); - } - - s->mEnviroment.mFieldCount = bccGetExportVarCount(s->mBccScript); - if (s->mEnviroment.mFieldCount <= 0) - s->mEnviroment.mFieldAddress = NULL; - else { - s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *)); - bccGetExportVarList(s->mBccScript, s->mEnviroment.mFieldCount, (void **) s->mEnviroment.mFieldAddress); - s->initSlots(); - } + rsc->mHal.funcs.script.init(rsc, this, resName, cacheDir, bitcode, bitcodeLen, 0); - s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); - s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); - s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); - s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); + mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); + mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); + mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); + mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); - const static int pragmaMax = 16; - size_t pragmaCount = bccGetPragmaCount(s->mBccScript); - char const *keys[pragmaMax]; - char const *values[pragmaMax]; - bccGetPragmaList(s->mBccScript, pragmaMax, keys, values); + rsc->mHal.funcs.script.invokeInit(rsc, this); - for (size_t i=0; i < pragmaCount; ++i) { + for (size_t i=0; i < mHal.info.exportedPragmaCount; ++i) { + const char * key = mHal.info.exportedPragmaKeyList[i]; + const char * value = mHal.info.exportedPragmaValueList[i]; //LOGE("pragma %s %s", keys[i], values[i]); - if (!strcmp(keys[i], "version")) { - if (!strcmp(values[i], "1")) { + if (!strcmp(key, "version")) { + if (!strcmp(value, "1")) { continue; } - LOGE("Invalid version pragma value: %s\n", values[i]); + LOGE("Invalid version pragma value: %s\n", value); return false; } - if (!strcmp(keys[i], "stateVertex")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateVertex")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mVertex.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mVertex.clear(); continue; } - LOGE("Unrecognized value %s passed to stateVertex", values[i]); + LOGE("Unrecognized value %s passed to stateVertex", value); return false; } - if (!strcmp(keys[i], "stateRaster")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateRaster")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mRaster.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mRaster.clear(); continue; } - LOGE("Unrecognized value %s passed to stateRaster", values[i]); + LOGE("Unrecognized value %s passed to stateRaster", value); return false; } - if (!strcmp(keys[i], "stateFragment")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateFragment")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mFragment.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mFragment.clear(); continue; } - LOGE("Unrecognized value %s passed to stateFragment", values[i]); + LOGE("Unrecognized value %s passed to stateFragment", value); return false; } - if (!strcmp(keys[i], "stateStore")) { - if (!strcmp(values[i], "default")) { + if (!strcmp(key, "stateStore")) { + if (!strcmp(value, "default")) { continue; } - if (!strcmp(values[i], "parent")) { - s->mEnviroment.mFragmentStore.clear(); + if (!strcmp(value, "parent")) { + mEnviroment.mFragmentStore.clear(); continue; } - LOGE("Unrecognized value %s passed to stateStore", values[i]); + LOGE("Unrecognized value %s passed to stateStore", value); return false; } } - size_t objectSlotCount = bccGetObjectSlotCount(s->mBccScript); - uint32_t *objectSlots = NULL; - if (objectSlotCount) { - objectSlots = new uint32_t[objectSlotCount]; - bccGetObjectSlotList(s->mBccScript, objectSlotCount, objectSlots); - s->mProgram.mObjectSlotList = objectSlots; - s->mProgram.mObjectSlotCount = objectSlotCount; - } + mSlots = new ObjectBaseRef<Allocation>[mHal.info.exportedVariableCount]; + mTypes = new ObjectBaseRef<const Type>[mHal.info.exportedVariableCount]; return true; } @@ -610,39 +261,20 @@ bool ScriptCState::runCompiler(Context *rsc, namespace android { namespace renderscript { -void rsi_ScriptCBegin(Context * rsc) { -} - -void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { - ScriptCState *ss = &rsc->mScriptC; - - char *t = (char *)malloc(len + 1); - memcpy(t, text, len); - t[len] = 0; - ss->mScriptText = t; - ss->mScriptLen = len; -} - - RsScript rsi_ScriptCCreate(Context *rsc, - const char *packageName /* deprecated */, - const char *resName, - const char *cacheDir) + const char *resName, size_t resName_length, + const char *cacheDir, size_t cacheDir_length, + const char *text, size_t text_length) { - ScriptCState *ss = &rsc->mScriptC; - ScriptC *s = new ScriptC(rsc); - s->mEnviroment.mScriptText = ss->mScriptText; - s->mEnviroment.mScriptTextLength = ss->mScriptLen; - ss->mScriptText = NULL; - ss->mScriptLen = 0; - s->incUserRef(); - if (!ss->runCompiler(rsc, s, resName, cacheDir)) { + if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) { // Error during compile, destroy s and return null. delete s; return NULL; } + + s->incUserRef(); return s; } diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 2c74b5b..5c191d9 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -21,7 +21,6 @@ #include "RenderScriptEnv.h" -struct BCCOpaqueScript; // --------------------------------------------------------------------------- namespace android { @@ -36,26 +35,11 @@ public: ScriptC(Context *); virtual ~ScriptC(); - struct Program_t { - int mVersionMajor; - int mVersionMinor; - - RunScript_t mRoot; - VoidFunc_t mInit; - - uint32_t * mObjectSlotList; - uint32_t mObjectSlotCount; - }; - - - Program_t mProgram; - - BCCOpaqueScript *mBccScript; const Allocation *ptrToAllocation(const void *) const; - virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len); + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, size_t len); virtual uint32_t run(Context *); @@ -63,13 +47,17 @@ public: const Allocation * ain, Allocation * aout, const void * usr, + size_t usrBytes, const RsScriptCall *sc = NULL); virtual void serialize(OStream *stream) const { } virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SCRIPT_C; } static Type *createFromStream(Context *rsc, IStream *stream) { return NULL; } -protected: + bool runCompiler(Context *rsc, const char *resName, const char *cacheDir, + const uint8_t *bitcode, size_t bitcodeLen); + +//protected: void setupScript(Context *); void setupGLState(Context *); Script * setTLS(Script *); @@ -83,8 +71,6 @@ public: char * mScriptText; size_t mScriptLen; - bool runCompiler(Context *rsc, ScriptC *s, const char *resName, const char *cacheDir); - struct SymbolTable_t { const char * mName; void * mPtr; diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index 8a4789a..4ee0a3e 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -16,7 +16,9 @@ #include "rsContext.h" #include "rsScriptC.h" -#include "rsMatrix.h" +#include "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" #include "utils/Timers.h" @@ -25,10 +27,9 @@ using namespace android; using namespace android::renderscript; -#define GET_TLS() Context::ScriptTLSStruct * tls = \ - (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ - Context * rsc = tls->mContext; \ - ScriptC * sc = (ScriptC *) tls->mScript + +namespace android { +namespace renderscript { ////////////////////////////////////////////////////////////////////////////// @@ -73,44 +74,15 @@ static float SC_cosf_fast(float x) { } #endif -static float SC_randf(float max) { - float r = (float)rand(); - r *= max; - r /= RAND_MAX; - return r; -} - -static float SC_randf2(float min, float max) { - float r = (float)rand(); - r /= RAND_MAX; - r = r * (max - min) + min; - return r; -} - -static int SC_randi(int max) { - return (int)SC_randf(max); -} - -static int SC_randi2(int min, int max) { - return (int)SC_randf2(min, max); -} - -static float SC_frac(float v) { - int i = (int)floor(v); - return fmin(v - i, 0x1.fffffep-1f); -} - ////////////////////////////////////////////////////////////////////////////// // Time routines ////////////////////////////////////////////////////////////////////////////// -static time_t SC_time(time_t *timer) { - GET_TLS(); +time_t rsrTime(Context *rsc, Script *sc, time_t *timer) { return time(timer); } -static tm* SC_localtime(tm *local, time_t *timer) { - GET_TLS(); +tm* rsrLocalTime(Context *rsc, Script *sc, tm *local, time_t *timer) { if (!local) { return NULL; } @@ -124,16 +96,15 @@ static tm* SC_localtime(tm *local, time_t *timer) { return local; } -static int64_t SC_uptimeMillis() { +int64_t rsrUptimeMillis(Context *rsc, Script *sc) { return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); } -static int64_t SC_uptimeNanos() { +int64_t rsrUptimeNanos(Context *rsc, Script *sc) { return systemTime(SYSTEM_TIME_MONOTONIC); } -static float SC_getDt() { - GET_TLS(); +float rsrGetDt(Context *rsc, Script *sc) { int64_t l = sc->mEnviroment.mLastDtTime; sc->mEnviroment.mLastDtTime = systemTime(SYSTEM_TIME_MONOTONIC); return ((float)(sc->mEnviroment.mLastDtTime - l)) / 1.0e9; @@ -143,883 +114,61 @@ static float SC_getDt() { // ////////////////////////////////////////////////////////////////////////////// -static uint32_t SC_allocGetDimX(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - //LOGE("SC_allocGetDimX a=%p type=%p", a, a->getType()); - return a->getType()->getDimX(); -} - -static uint32_t SC_allocGetDimY(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - return a->getType()->getDimY(); -} - -static uint32_t SC_allocGetDimZ(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - return a->getType()->getDimZ(); -} - -static uint32_t SC_allocGetDimLOD(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - return a->getType()->getDimLOD(); -} - -static uint32_t SC_allocGetDimFaces(RsAllocation va) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - return a->getType()->getDimFaces(); -} - -static const void * SC_getElementAtX(RsAllocation va, uint32_t x) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); - const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * x]; -} - -static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); - const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * (x + y*t->getDimX())]; -} - -static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z) { - const Allocation *a = static_cast<const Allocation *>(va); - CHECK_OBJ(a); - const Type *t = a->getType(); - CHECK_OBJ(t); - const uint8_t *p = (const uint8_t *)a->getPtr(); - return &p[t->getElementSizeBytes() * (x + y*t->getDimX())]; -} - -static void SC_setObject(void **vdst, void * vsrc) { - //LOGE("SC_setObject %p,%p %p", vdst, *vdst, vsrc); - if (vsrc) { - CHECK_OBJ(vsrc); - static_cast<ObjectBase *>(vsrc)->incSysRef(); +void rsrSetObject(const Context *rsc, const Script *sc, ObjectBase **dst, ObjectBase * src) { + //LOGE("rsiSetObject %p,%p %p", vdst, *vdst, vsrc); + if (src) { + CHECK_OBJ(src); + src->incSysRef(); } - if (vdst[0]) { - CHECK_OBJ(vdst[0]); - static_cast<ObjectBase *>(vdst[0])->decSysRef(); + if (dst[0]) { + CHECK_OBJ(dst[0]); + dst[0]->decSysRef(); } - *vdst = vsrc; - //LOGE("SC_setObject *"); + *dst = src; } -static void SC_clearObject(void **vdst) { - //LOGE("SC_clearObject %p,%p", vdst, *vdst); - if (vdst[0]) { - CHECK_OBJ(vdst[0]); - static_cast<ObjectBase *>(vdst[0])->decSysRef(); +void rsrClearObject(const Context *rsc, const Script *sc, ObjectBase **dst) { + //LOGE("rsiClearObject %p,%p", vdst, *vdst); + if (dst[0]) { + CHECK_OBJ(dst[0]); + dst[0]->decSysRef(); } - *vdst = NULL; - //LOGE("SC_clearObject *"); + *dst = NULL; } -static bool SC_isObject(RsAllocation vsrc) { - return vsrc != NULL; +bool rsrIsObject(const Context *rsc, const Script *sc, const ObjectBase *src) { + return src != NULL; } -static void SC_debugF(const char *s, float f) { - LOGD("%s %f, 0x%08x", s, f, *((int *) (&f))); -} -static void SC_debugFv2(const char *s, float f1, float f2) { - LOGD("%s {%f, %f}", s, f1, f2); -} -static void SC_debugFv3(const char *s, float f1, float f2, float f3) { - LOGD("%s {%f, %f, %f}", s, f1, f2, f3); -} -static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) { - LOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); -} -static void SC_debugD(const char *s, double d) { - LOGD("%s %f, 0x%08llx", s, d, *((long long *) (&d))); -} -static void SC_debugFM4v4(const char *s, const float *f) { - LOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); - LOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); - LOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); - LOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); -} -static void SC_debugFM3v3(const char *s, const float *f) { - LOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]); - LOGD("%s %f, %f, %f", s, f[1], f[4], f[7]); - LOGD("%s %f, %f, %f}",s, f[2], f[5], f[8]); -} -static void SC_debugFM2v2(const char *s, const float *f) { - LOGD("%s {%f, %f", s, f[0], f[2]); - LOGD("%s %f, %f}",s, f[1], f[3]); -} -static void SC_debugI32(const char *s, int32_t i) { - LOGD("%s %i 0x%x", s, i, i); -} -static void SC_debugU32(const char *s, uint32_t i) { - LOGD("%s %u 0x%x", s, i, i); -} -static void SC_debugLL64(const char *s, long long ll) { - LOGD("%s %lld 0x%llx", s, ll, ll); -} -static void SC_debugULL64(const char *s, unsigned long long ll) { - LOGD("%s %llu 0x%llx", s, ll, ll); -} - -static void SC_debugP(const char *s, const void *p) { - LOGD("%s %p", s, p); -} - -static uint32_t SC_toClient2(int cmdID, void *data, int len) { - GET_TLS(); +uint32_t rsrToClient(Context *rsc, Script *sc, int cmdID, void *data, int len) { //LOGE("SC_toClient %i %i %i", cmdID, len); return rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, cmdID, len, false); } -static uint32_t SC_toClient(int cmdID) { - GET_TLS(); - //LOGE("SC_toClient %i", cmdID); - return rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_USER, cmdID, 0, false); -} - -static uint32_t SC_toClientBlocking2(int cmdID, void *data, int len) { - GET_TLS(); +uint32_t rsrToClientBlocking(Context *rsc, Script *sc, int cmdID, void *data, int len) { //LOGE("SC_toClientBlocking %i %i", cmdID, len); return rsc->sendMessageToClient(data, RS_MESSAGE_TO_CLIENT_USER, cmdID, len, true); } -static uint32_t SC_toClientBlocking(int cmdID) { - GET_TLS(); - //LOGE("SC_toClientBlocking %i", cmdID); - return rsc->sendMessageToClient(NULL, RS_MESSAGE_TO_CLIENT_USER, cmdID, 0, true); -} - -int SC_divsi3(int a, int b) { - return a / b; -} - -int SC_modsi3(int a, int b) { - return a % b; -} - -unsigned int SC_udivsi3(unsigned int a, unsigned int b) { - return a / b; -} - -unsigned int SC_umodsi3(unsigned int a, unsigned int b) { - return a % b; -} - -int SC_getAllocation(const void *ptr) { - GET_TLS(); - const Allocation *alloc = sc->ptrToAllocation(ptr); - return (int)alloc; -} -void SC_allocationMarkDirty(RsAllocation a) { - Allocation *alloc = static_cast<Allocation *>(a); - alloc->sendDirty(); -} - -void SC_ForEach(RsScript vs, - RsAllocation vin, - RsAllocation vout, - const void *usr) { - GET_TLS(); - const Allocation *ain = static_cast<const Allocation *>(vin); - Allocation *aout = static_cast<Allocation *>(vout); - Script *s = static_cast<Script *>(vs); - s->runForEach(rsc, ain, aout, usr); -} - -void SC_ForEach2(RsScript vs, - RsAllocation vin, - RsAllocation vout, - const void *usr, +void rsrForEach(Context *rsc, Script *sc, + Script *target, + Allocation *in, Allocation *out, + const void *usr, uint32_t usrBytes, const RsScriptCall *call) { - GET_TLS(); - const Allocation *ain = static_cast<const Allocation *>(vin); - Allocation *aout = static_cast<Allocation *>(vout); - Script *s = static_cast<Script *>(vs); - s->runForEach(rsc, ain, aout, usr, call); -} - - -////////////////////////////////////////////////////////////////////////////// -// Heavy math functions -////////////////////////////////////////////////////////////////////////////// - -typedef struct { - float m[16]; -} rs_matrix4x4; - -typedef struct { - float m[9]; -} rs_matrix3x3; - -typedef struct { - float m[4]; -} rs_matrix2x2; - -static inline void -rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 4 + col] = v; -} - -static inline float -rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) { - return m->m[row * 4 + col]; -} - -static inline void -rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 3 + col] = v; -} - -static inline float -rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) { - return m->m[row * 3 + col]; -} - -static inline void -rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) { - m->m[row * 2 + col] = v; -} - -static inline float -rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) { - return m->m[row * 2 + col]; -} - - -static void SC_MatrixLoadIdentity_4x4(rs_matrix4x4 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = 0.f; - m->m[5] = 1.f; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = 0.f; - m->m[9] = 0.f; - m->m[10] = 1.f; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void SC_MatrixLoadIdentity_3x3(rs_matrix3x3 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = 1.f; - m->m[5] = 0.f; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = 1.f; -} - -static void SC_MatrixLoadIdentity_2x2(rs_matrix2x2 *m) { - m->m[0] = 1.f; - m->m[1] = 0.f; - m->m[2] = 0.f; - m->m[3] = 1.f; -} - -static void SC_MatrixLoad_4x4_f(rs_matrix4x4 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; - m->m[4] = v[4]; - m->m[5] = v[5]; - m->m[6] = v[6]; - m->m[7] = v[7]; - m->m[8] = v[8]; - m->m[9] = v[9]; - m->m[10] = v[10]; - m->m[11] = v[11]; - m->m[12] = v[12]; - m->m[13] = v[13]; - m->m[14] = v[14]; - m->m[15] = v[15]; -} - -static void SC_MatrixLoad_3x3_f(rs_matrix3x3 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; - m->m[4] = v[4]; - m->m[5] = v[5]; - m->m[6] = v[6]; - m->m[7] = v[7]; - m->m[8] = v[8]; -} - -static void SC_MatrixLoad_2x2_f(rs_matrix2x2 *m, const float *v) { - m->m[0] = v[0]; - m->m[1] = v[1]; - m->m[2] = v[2]; - m->m[3] = v[3]; -} - -static void SC_MatrixLoad_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; - m->m[4] = v->m[4]; - m->m[5] = v->m[5]; - m->m[6] = v->m[6]; - m->m[7] = v->m[7]; - m->m[8] = v->m[8]; - m->m[9] = v->m[9]; - m->m[10] = v->m[10]; - m->m[11] = v->m[11]; - m->m[12] = v->m[12]; - m->m[13] = v->m[13]; - m->m[14] = v->m[14]; - m->m[15] = v->m[15]; -} - -static void SC_MatrixLoad_4x4_3x3(rs_matrix4x4 *m, const rs_matrix3x3 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = 0.f; - m->m[4] = v->m[3]; - m->m[5] = v->m[4]; - m->m[6] = v->m[5]; - m->m[7] = 0.f; - m->m[8] = v->m[6]; - m->m[9] = v->m[7]; - m->m[10] = v->m[8]; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void SC_MatrixLoad_4x4_2x2(rs_matrix4x4 *m, const rs_matrix2x2 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = 0.f; - m->m[3] = 0.f; - m->m[4] = v->m[2]; - m->m[5] = v->m[3]; - m->m[6] = 0.f; - m->m[7] = 0.f; - m->m[8] = 0.f; - m->m[9] = 0.f; - m->m[10] = 1.f; - m->m[11] = 0.f; - m->m[12] = 0.f; - m->m[13] = 0.f; - m->m[14] = 0.f; - m->m[15] = 1.f; -} - -static void SC_MatrixLoad_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; - m->m[4] = v->m[4]; - m->m[5] = v->m[5]; - m->m[6] = v->m[6]; - m->m[7] = v->m[7]; - m->m[8] = v->m[8]; -} - -static void SC_MatrixLoad_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *v) { - m->m[0] = v->m[0]; - m->m[1] = v->m[1]; - m->m[2] = v->m[2]; - m->m[3] = v->m[3]; -} - -static void SC_MatrixLoadRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { - float c, s; - m->m[3] = 0; - m->m[7] = 0; - m->m[11]= 0; - m->m[12]= 0; - m->m[13]= 0; - m->m[14]= 0; - m->m[15]= 1; - rot *= (float)(M_PI / 180.0f); - c = cos(rot); - s = sin(rot); - - const float len = x*x + y*y + z*z; - if (len != 1) { - const float recipLen = 1.f / sqrt(len); - x *= recipLen; - y *= recipLen; - z *= recipLen; - } - const float nc = 1.0f - c; - const float xy = x * y; - const float yz = y * z; - const float zx = z * x; - const float xs = x * s; - const float ys = y * s; - const float zs = z * s; - m->m[ 0] = x*x*nc + c; - m->m[ 4] = xy*nc - zs; - m->m[ 8] = zx*nc + ys; - m->m[ 1] = xy*nc + zs; - m->m[ 5] = y*y*nc + c; - m->m[ 9] = yz*nc - xs; - m->m[ 2] = zx*nc - ys; - m->m[ 6] = yz*nc + xs; - m->m[10] = z*z*nc + c; -} - -static void SC_MatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) { - SC_MatrixLoadIdentity_4x4(m); - m->m[0] = x; - m->m[5] = y; - m->m[10] = z; -} - -static void SC_MatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) { - SC_MatrixLoadIdentity_4x4(m); - m->m[12] = x; - m->m[13] = y; - m->m[14] = z; -} - -static void SC_MatrixLoadMultiply_4x4_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) { - for (int i=0 ; i<4 ; i++) { - float ri0 = 0; - float ri1 = 0; - float ri2 = 0; - float ri3 = 0; - for (int j=0 ; j<4 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; - ri3 += rsMatrixGet(lhs, j, 3) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - rsMatrixSet(m, i, 2, ri2); - rsMatrixSet(m, i, 3, ri3); - } -} - -static void SC_MatrixMultiply_4x4_4x4(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) { - rs_matrix4x4 mt; - SC_MatrixLoadMultiply_4x4_4x4_4x4(&mt, m, rhs); - SC_MatrixLoad_4x4_4x4(m, &mt); -} - -static void SC_MatrixLoadMultiply_3x3_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *lhs, const rs_matrix3x3 *rhs) { - for (int i=0 ; i<3 ; i++) { - float ri0 = 0; - float ri1 = 0; - float ri2 = 0; - for (int j=0 ; j<3 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - ri2 += rsMatrixGet(lhs, j, 2) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - rsMatrixSet(m, i, 2, ri2); - } -} - -static void SC_MatrixMultiply_3x3_3x3(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) { - rs_matrix3x3 mt; - SC_MatrixLoadMultiply_3x3_3x3_3x3(&mt, m, rhs); - SC_MatrixLoad_3x3_3x3(m, &mt); -} - -static void SC_MatrixLoadMultiply_2x2_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *lhs, const rs_matrix2x2 *rhs) { - for (int i=0 ; i<2 ; i++) { - float ri0 = 0; - float ri1 = 0; - for (int j=0 ; j<2 ; j++) { - const float rhs_ij = rsMatrixGet(rhs, i,j); - ri0 += rsMatrixGet(lhs, j, 0) * rhs_ij; - ri1 += rsMatrixGet(lhs, j, 1) * rhs_ij; - } - rsMatrixSet(m, i, 0, ri0); - rsMatrixSet(m, i, 1, ri1); - } -} - -static void SC_MatrixMultiply_2x2_2x2(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) { - rs_matrix2x2 mt; - SC_MatrixLoadMultiply_2x2_2x2_2x2(&mt, m, rhs); - SC_MatrixLoad_2x2_2x2(m, &mt); -} - -static void SC_MatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { - rs_matrix4x4 m1; - SC_MatrixLoadRotate(&m1, rot, x, y, z); - SC_MatrixMultiply_4x4_4x4(m, &m1); -} - -static void SC_MatrixScale(rs_matrix4x4 *m, float x, float y, float z) { - rs_matrix4x4 m1; - SC_MatrixLoadScale(&m1, x, y, z); - SC_MatrixMultiply_4x4_4x4(m, &m1); + target->runForEach(rsc, in, out, usr, usrBytes, call); } -static void SC_MatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) { - rs_matrix4x4 m1; - SC_MatrixLoadTranslate(&m1, x, y, z); - SC_MatrixMultiply_4x4_4x4(m, &m1); -} - -static void SC_MatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { - SC_MatrixLoadIdentity_4x4(m); - m->m[0] = 2.f / (right - left); - m->m[5] = 2.f / (top - bottom); - m->m[10]= -2.f / (far - near); - m->m[12]= -(right + left) / (right - left); - m->m[13]= -(top + bottom) / (top - bottom); - m->m[14]= -(far + near) / (far - near); -} - -static void SC_MatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { - SC_MatrixLoadIdentity_4x4(m); - m->m[0] = 2.f * near / (right - left); - m->m[5] = 2.f * near / (top - bottom); - m->m[8] = (right + left) / (right - left); - m->m[9] = (top + bottom) / (top - bottom); - m->m[10]= -(far + near) / (far - near); - m->m[11]= -1.f; - m->m[14]= -2.f * far * near / (far - near); - m->m[15]= 0.f; -} - -static void SC_MatrixLoadPerspective(rs_matrix4x4* m, float fovy, float aspect, float near, float far) { - float top = near * tan((float) (fovy * M_PI / 360.0f)); - float bottom = -top; - float left = bottom * aspect; - float right = top * aspect; - SC_MatrixLoadFrustum(m, left, right, bottom, top, near, far); -} - - -// Returns true if the matrix was successfully inversed -static bool SC_MatrixInverse_4x4(rs_matrix4x4 *m) { - rs_matrix4x4 result; - - int i, j; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - // computeCofactor for int i, int j - int c0 = (i+1) % 4; - int c1 = (i+2) % 4; - int c2 = (i+3) % 4; - int r0 = (j+1) % 4; - int r1 = (j+2) % 4; - int r2 = (j+3) % 4; - - float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) - - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) - + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); - - float cofactor = (i+j) & 1 ? -minor : minor; - - result.m[4*i + j] = cofactor; - } - } - - // Dot product of 0th column of source and 0th row of result - float det = m->m[0]*result.m[0] + m->m[4]*result.m[1] + - m->m[8]*result.m[2] + m->m[12]*result.m[3]; - - if (fabs(det) < 1e-6) { - return false; - } - - det = 1.0f / det; - for (i = 0; i < 16; ++i) { - m->m[i] = result.m[i] * det; - } - - return true; -} - -// Returns true if the matrix was successfully inversed -static bool SC_MatrixInverseTranspose_4x4(rs_matrix4x4 *m) { - rs_matrix4x4 result; - - int i, j; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - // computeCofactor for int i, int j - int c0 = (i+1) % 4; - int c1 = (i+2) % 4; - int c2 = (i+3) % 4; - int r0 = (j+1) % 4; - int r1 = (j+2) % 4; - int r2 = (j+3) % 4; - - float minor = (m->m[c0 + 4*r0] * (m->m[c1 + 4*r1] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r1])) - - (m->m[c0 + 4*r1] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r2] - m->m[c1 + 4*r2] * m->m[c2 + 4*r0])) - + (m->m[c0 + 4*r2] * (m->m[c1 + 4*r0] * m->m[c2 + 4*r1] - m->m[c1 + 4*r1] * m->m[c2 + 4*r0])); - - float cofactor = (i+j) & 1 ? -minor : minor; - - result.m[4*j + i] = cofactor; - } - } - - // Dot product of 0th column of source and 0th column of result - float det = m->m[0]*result.m[0] + m->m[4]*result.m[4] + - m->m[8]*result.m[8] + m->m[12]*result.m[12]; - - if (fabs(det) < 1e-6) { - return false; - } - - det = 1.0f / det; - for (i = 0; i < 16; ++i) { - m->m[i] = result.m[i] * det; - } - - return true; +void rsrAllocationSyncAll(Context *rsc, Script *sc, Allocation *a, RsAllocationUsageType usage) { + a->syncAll(rsc, usage); } -static void SC_MatrixTranspose_4x4(rs_matrix4x4 *m) { - int i, j; - float temp; - for (i = 0; i < 3; ++i) { - for (j = i + 1; j < 4; ++j) { - temp = m->m[i*4 + j]; - m->m[i*4 + j] = m->m[j*4 + i]; - m->m[j*4 + i] = temp; - } - } +const Allocation * rsrGetAllocation(Context *rsc, Script *s, const void *ptr) { + ScriptC *sc = (ScriptC *)s; + return sc->ptrToAllocation(ptr); } -static void SC_MatrixTranspose_3x3(rs_matrix3x3 *m) { - int i, j; - float temp; - for (i = 0; i < 2; ++i) { - for (j = i + 1; j < 3; ++j) { - temp = m->m[i*3 + j]; - m->m[i*3 + j] = m->m[j*4 + i]; - m->m[j*3 + i] = temp; - } - } } - -static void SC_MatrixTranspose_2x2(rs_matrix2x2 *m) { - float temp = m->m[1]; - m->m[1] = m->m[2]; - m->m[2] = temp; } - -////////////////////////////////////////////////////////////////////////////// -// Class implementation -////////////////////////////////////////////////////////////////////////////// - -// llvm name mangling ref -// <builtin-type> ::= v # void -// ::= b # bool -// ::= c # char -// ::= a # signed char -// ::= h # unsigned char -// ::= s # short -// ::= t # unsigned short -// ::= i # int -// ::= j # unsigned int -// ::= l # long -// ::= m # unsigned long -// ::= x # long long, __int64 -// ::= y # unsigned long long, __int64 -// ::= f # float -// ::= d # double - -static ScriptCState::SymbolTable_t gSyms[] = { - { "__divsi3", (void *)&SC_divsi3, true }, - { "__modsi3", (void *)&SC_modsi3, true }, - { "__udivsi3", (void *)&SC_udivsi3, true }, - { "__umodsi3", (void *)&SC_umodsi3, true }, - { "memset", (void *)&memset, true }, - { "memcpy", (void *)&memcpy, true }, - - // allocation - { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true }, - { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true }, - { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true }, - { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true }, - { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true }, - { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true }, - - { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true }, - { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true }, - { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true }, - - { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true }, - - { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true }, - { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true }, - { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true }, - - - { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true }, - - - // Debug - { "_Z7rsDebugPKcf", (void *)&SC_debugF, true }, - { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true }, - { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true }, - { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true }, - { "_Z7rsDebugPKcd", (void *)&SC_debugD, true }, - { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true }, - { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true }, - { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true }, - { "_Z7rsDebugPKci", (void *)&SC_debugI32, true }, - { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true }, - // Both "long" and "unsigned long" need to be redirected to their - // 64-bit counterparts, since we have hacked Slang to use 64-bit - // for "long" on Arm (to be similar to Java). - { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true }, - { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true }, - { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true }, - { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true }, - { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true }, - - // RS Math - { "_Z6rsRandi", (void *)&SC_randi, true }, - { "_Z6rsRandii", (void *)&SC_randi2, true }, - { "_Z6rsRandf", (void *)&SC_randf, true }, - { "_Z6rsRandff", (void *)&SC_randf2, true }, - { "_Z6rsFracf", (void *)&SC_frac, true }, - - // time - { "_Z6rsTimePi", (void *)&SC_time, true }, - { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true }, - { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true }, - { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true }, - { "_Z7rsGetDtv", (void*)&SC_getDt, false }, - - { "_Z14rsSendToClienti", (void *)&SC_toClient, false }, - { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2, false }, - { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false }, - { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false }, - - // matrix - { "_Z20rsMatrixLoadIdentityP12rs_matrix4x4", (void *)&SC_MatrixLoadIdentity_4x4, true }, - { "_Z20rsMatrixLoadIdentityP12rs_matrix3x3", (void *)&SC_MatrixLoadIdentity_3x3, true }, - { "_Z20rsMatrixLoadIdentityP12rs_matrix2x2", (void *)&SC_MatrixLoadIdentity_2x2, true }, - - { "_Z12rsMatrixLoadP12rs_matrix4x4PKf", (void *)&SC_MatrixLoad_4x4_f, true }, - { "_Z12rsMatrixLoadP12rs_matrix3x3PKf", (void *)&SC_MatrixLoad_3x3_f, true }, - { "_Z12rsMatrixLoadP12rs_matrix2x2PKf", (void *)&SC_MatrixLoad_2x2_f, true }, - - { "_Z12rsMatrixLoadP12rs_matrix4x4PKS_", (void *)&SC_MatrixLoad_4x4_4x4, true }, - { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", (void *)&SC_MatrixLoad_4x4_3x3, true }, - { "_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", (void *)&SC_MatrixLoad_4x4_2x2, true }, - { "_Z12rsMatrixLoadP12rs_matrix3x3PKS_", (void *)&SC_MatrixLoad_3x3_3x3, true }, - { "_Z12rsMatrixLoadP12rs_matrix2x2PKS_", (void *)&SC_MatrixLoad_2x2_2x2, true }, - - { "_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadRotate, true }, - { "_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", (void *)&SC_MatrixLoadScale, true }, - { "_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixLoadTranslate, true }, - { "_Z14rsMatrixRotateP12rs_matrix4x4ffff", (void *)&SC_MatrixRotate, true }, - { "_Z13rsMatrixScaleP12rs_matrix4x4fff", (void *)&SC_MatrixScale, true }, - { "_Z17rsMatrixTranslateP12rs_matrix4x4fff", (void *)&SC_MatrixTranslate, true }, - - { "_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", (void *)&SC_MatrixLoadMultiply_4x4_4x4_4x4, true }, - { "_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", (void *)&SC_MatrixMultiply_4x4_4x4, true }, - { "_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", (void *)&SC_MatrixLoadMultiply_3x3_3x3_3x3, true }, - { "_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", (void *)&SC_MatrixMultiply_3x3_3x3, true }, - { "_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", (void *)&SC_MatrixLoadMultiply_2x2_2x2_2x2, true }, - { "_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", (void *)&SC_MatrixMultiply_2x2_2x2, true }, - - { "_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadOrtho, true }, - { "_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", (void *)&SC_MatrixLoadFrustum, true }, - { "_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", (void *)&SC_MatrixLoadPerspective, true }, - - { "_Z15rsMatrixInverseP12rs_matrix4x4", (void *)&SC_MatrixInverse_4x4, true }, - { "_Z24rsMatrixInverseTransposeP12rs_matrix4x4", (void *)&SC_MatrixInverseTranspose_4x4, true }, - { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_4x4, true }, - { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_3x3, true }, - { "_Z17rsMatrixTransposeP12rs_matrix4x4", (void *)&SC_MatrixTranspose_2x2, true }, - - { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false }, - //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true }, - -//////////////////////////////////////////////////////////////////// - - //{ "sinf_fast", (void *)&SC_sinf_fast, true }, - //{ "cosf_fast", (void *)&SC_cosf_fast, true }, - - { NULL, NULL, false } -}; - -const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym) { - ScriptCState::SymbolTable_t *syms = gSyms; - - while (syms->mPtr) { - if (!strcmp(syms->mName, sym)) { - return syms; - } - syms++; - } - return NULL; -} diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index 15426bc..3259cb4 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -16,9 +16,14 @@ #include "rsContext.h" #include "rsScriptC.h" -#include "rsMatrix.h" +#include "rsMatrix4x4.h" +#include "rsMatrix3x3.h" +#include "rsMatrix2x2.h" #include "utils/Timers.h" +#include "driver/rsdVertexArray.h" +#include "driver/rsdShaderCache.h" +#include "driver/rsdCore.h" #define GL_GLEXT_PROTOTYPES @@ -32,88 +37,90 @@ using namespace android; using namespace android::renderscript; -#define GET_TLS() Context::ScriptTLSStruct * tls = \ - (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \ - Context * rsc = tls->mContext; \ - ScriptC * sc = (ScriptC *) tls->mScript - +namespace android { +namespace renderscript { ////////////////////////////////////////////////////////////////////////////// // Context ////////////////////////////////////////////////////////////////////////////// -static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va) { - CHECK_OBJ_OR_NULL(va); - CHECK_OBJ(vpf); - GET_TLS(); - rsi_ProgramBindTexture(rsc, - static_cast<ProgramFragment *>(vpf), - slot, - static_cast<Allocation *>(va)); +void rsrBindTexture(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) { + CHECK_OBJ_OR_NULL(a); + CHECK_OBJ(pf); + pf->bindTexture(rsc, slot, a); } -static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs) { +void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) { CHECK_OBJ_OR_NULL(vs); CHECK_OBJ(vpf); - GET_TLS(); - rsi_ProgramBindSampler(rsc, - static_cast<ProgramFragment *>(vpf), - slot, - static_cast<Sampler *>(vs)); + pf->bindSampler(rsc, slot, s); } -static void SC_bindProgramStore(RsProgramStore pfs) { - CHECK_OBJ_OR_NULL(pfs); - GET_TLS(); - rsi_ContextBindProgramStore(rsc, pfs); +void rsrBindProgramStore(Context *rsc, Script *sc, ProgramStore *ps) { + CHECK_OBJ_OR_NULL(ps); + rsc->setProgramStore(ps); } -static void SC_bindProgramFragment(RsProgramFragment pf) { +void rsrBindProgramFragment(Context *rsc, Script *sc, ProgramFragment *pf) { CHECK_OBJ_OR_NULL(pf); - GET_TLS(); - rsi_ContextBindProgramFragment(rsc, pf); + rsc->setProgramFragment(pf); } -static void SC_bindProgramVertex(RsProgramVertex pv) { +void rsrBindProgramVertex(Context *rsc, Script *sc, ProgramVertex *pv) { CHECK_OBJ_OR_NULL(pv); - GET_TLS(); - rsi_ContextBindProgramVertex(rsc, pv); + rsc->setProgramVertex(pv); } -static void SC_bindProgramRaster(RsProgramRaster pv) { - CHECK_OBJ_OR_NULL(pv); - GET_TLS(); - rsi_ContextBindProgramRaster(rsc, pv); +void rsrBindProgramRaster(Context *rsc, Script *sc, ProgramRaster *pr) { + CHECK_OBJ_OR_NULL(pr); + rsc->setProgramRaster(pr); +} + +void rsrBindFrameBufferObjectColorTarget(Context *rsc, Script *sc, Allocation *a, uint32_t slot) { + CHECK_OBJ(va); + rsc->mFBOCache.bindColorTarget(rsc, a, slot); +} + +void rsrBindFrameBufferObjectDepthTarget(Context *rsc, Script *sc, Allocation *a) { + CHECK_OBJ(va); + rsc->mFBOCache.bindDepthTarget(rsc, a); +} + +void rsrClearFrameBufferObjectColorTarget(Context *rsc, Script *sc, uint32_t slot) { + rsc->mFBOCache.bindColorTarget(rsc, NULL, slot); +} + +void rsrClearFrameBufferObjectDepthTarget(Context *rsc, Script *sc) { + rsc->mFBOCache.bindDepthTarget(rsc, NULL); +} + +void rsrClearFrameBufferObjectTargets(Context *rsc, Script *sc) { + rsc->mFBOCache.resetAll(rsc); } ////////////////////////////////////////////////////////////////////////////// // VP ////////////////////////////////////////////////////////////////////////////// -static void SC_vpLoadProjectionMatrix(const rsc_Matrix *m) { - GET_TLS(); +void rsrVpLoadProjectionMatrix(Context *rsc, Script *sc, const rsc_Matrix *m) { rsc->getProgramVertex()->setProjectionMatrix(rsc, m); } -static void SC_vpLoadModelMatrix(const rsc_Matrix *m) { - GET_TLS(); +void rsrVpLoadModelMatrix(Context *rsc, Script *sc, const rsc_Matrix *m) { rsc->getProgramVertex()->setModelviewMatrix(rsc, m); } -static void SC_vpLoadTextureMatrix(const rsc_Matrix *m) { - GET_TLS(); +void rsrVpLoadTextureMatrix(Context *rsc, Script *sc, const rsc_Matrix *m) { rsc->getProgramVertex()->setTextureMatrix(rsc, m); } -static void SC_pfConstantColor(RsProgramFragment vpf, float r, float g, float b, float a) { - GET_TLS(); - CHECK_OBJ(vpf); - ProgramFragment *pf = static_cast<ProgramFragment *>(vpf); +void rsrPfConstantColor(Context *rsc, Script *sc, ProgramFragment *pf, + float r, float g, float b, float a) { + CHECK_OBJ(pf); pf->setConstantColor(rsc, r, g, b, a); } -static void SC_vpGetProjectionMatrix(rsc_Matrix *m) { - GET_TLS(); +void rsrVpGetProjectionMatrix(Context *rsc, Script *sc, rsc_Matrix *m) { rsc->getProgramVertex()->getProjectionMatrix(rsc, m); } @@ -121,19 +128,20 @@ static void SC_vpGetProjectionMatrix(rsc_Matrix *m) { // Drawing ////////////////////////////////////////////////////////////////////////////// -static void SC_drawQuadTexCoords(float x1, float y1, float z1, - float u1, float v1, - float x2, float y2, float z2, - float u2, float v2, - float x3, float y3, float z3, - float u3, float v3, - float x4, float y4, float z4, - float u4, float v4) { - GET_TLS(); +void rsrDrawQuadTexCoords(Context *rsc, Script *sc, + float x1, float y1, float z1, float u1, float v1, + float x2, float y2, float z2, float u2, float v2, + float x3, float y3, float z3, float u3, float v3, + float x4, float y4, float z4, float u4, float v4) { if (!rsc->setupCheck()) { return; } + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + //LOGE("Quad"); //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1); //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2); @@ -143,28 +151,29 @@ static void SC_drawQuadTexCoords(float x1, float y1, float z1, float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4}; const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4}; - VertexArray::Attrib attribs[2]; + RsdVertexArray::Attrib attribs[2]; attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position"); attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0"); - VertexArray va(attribs, 2); - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); + RsdVertexArray va(attribs, 2); + va.setup(rsc); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } -static void SC_drawQuad(float x1, float y1, float z1, - float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4) { - SC_drawQuadTexCoords(x1, y1, z1, 0, 1, - x2, y2, z2, 1, 1, - x3, y3, z3, 1, 0, - x4, y4, z4, 0, 0); +void rsrDrawQuad(Context *rsc, Script *sc, + float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4) { + rsrDrawQuadTexCoords(rsc, sc, x1, y1, z1, 0, 1, + x2, y2, z2, 1, 1, + x3, y3, z3, 1, 0, + x4, y4, z4, 0, 0); } -static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h) { - GET_TLS(); +void rsrDrawSpriteScreenspace(Context *rsc, Script *sc, + float x, float y, float z, float w, float h) { ObjectBaseRef<const ProgramVertex> tmp(rsc->getProgramVertex()); rsc->setProgramVertex(rsc->getDefaultProgramVertex()); //rsc->setupCheck(); @@ -173,87 +182,48 @@ static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h float sh = rsc->getHeight(); - SC_drawQuad(x, sh - y, z, + rsrDrawQuad(rsc, sc, + x, sh - y, z, x+w, sh - y, z, x+w, sh - (y+h), z, x, sh - (y+h), z); rsc->setProgramVertex((ProgramVertex *)tmp.get()); } -/* -static void SC_drawSprite(float x, float y, float z, float w, float h) -{ - GET_TLS(); - float vin[3] = {x, y, z}; - float vout[4]; - - //LOGE("ds in %f %f %f", x, y, z); - rsc->getVertex()->transformToScreen(rsc, vout, vin); - //LOGE("ds out %f %f %f %f", vout[0], vout[1], vout[2], vout[3]); - vout[0] /= vout[3]; - vout[1] /= vout[3]; - vout[2] /= vout[3]; - - vout[0] *= rsc->getWidth() / 2; - vout[1] *= rsc->getHeight() / 2; - vout[0] += rsc->getWidth() / 2; - vout[1] += rsc->getHeight() / 2; - - vout[0] -= w/2; - vout[1] -= h/2; - - //LOGE("ds out2 %f %f %f", vout[0], vout[1], vout[2]); - - // U, V, W, H - SC_drawSpriteScreenspace(vout[0], vout[1], z, h, w); - //rsc->setupCheck(); -} -*/ -static void SC_drawRect(float x1, float y1, - float x2, float y2, float z) { +void rsrDrawRect(Context *rsc, Script *sc, float x1, float y1, float x2, float y2, float z) { //LOGE("SC_drawRect %f,%f %f,%f %f", x1, y1, x2, y2, z); - SC_drawQuad(x1, y2, z, - x2, y2, z, - x2, y1, z, - x1, y1, z); + rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z); } -static void SC_drawMesh(RsMesh vsm) { - CHECK_OBJ(vsm); - GET_TLS(); - Mesh *sm = static_cast<Mesh *>(vsm); +void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) { + CHECK_OBJ(sm); if (!rsc->setupCheck()) { return; } sm->render(rsc); } -static void SC_drawMeshPrimitive(RsMesh vsm, uint32_t primIndex) { - CHECK_OBJ(vsm); - GET_TLS(); - Mesh *sm = static_cast<Mesh *>(vsm); +void rsrDrawMeshPrimitive(Context *rsc, Script *sc, Mesh *sm, uint32_t primIndex) { + CHECK_OBJ(sm); if (!rsc->setupCheck()) { return; } sm->renderPrimitive(rsc, primIndex); } -static void SC_drawMeshPrimitiveRange(RsMesh vsm, uint32_t primIndex, uint32_t start, uint32_t len) { - CHECK_OBJ(vsm); - GET_TLS(); - Mesh *sm = static_cast<Mesh *>(vsm); +void rsrDrawMeshPrimitiveRange(Context *rsc, Script *sc, Mesh *sm, uint32_t primIndex, + uint32_t start, uint32_t len) { + CHECK_OBJ(sm); if (!rsc->setupCheck()) { return; } sm->renderPrimitiveRange(rsc, primIndex, start, len); } -static void SC_meshComputeBoundingBox(RsMesh vsm, - float *minX, float *minY, float *minZ, - float *maxX, float *maxY, float *maxZ) { - CHECK_OBJ(vsm); - GET_TLS(); - Mesh *sm = static_cast<Mesh *>(vsm); +void rsrMeshComputeBoundingBox(Context *rsc, Script *sc, Mesh *sm, + float *minX, float *minY, float *minZ, + float *maxX, float *maxY, float *maxZ) { + CHECK_OBJ(sm); sm->computeBBox(); *minX = sm->mBBoxMin[0]; *minY = sm->mBBoxMin[1]; @@ -269,70 +239,53 @@ static void SC_meshComputeBoundingBox(RsMesh vsm, ////////////////////////////////////////////////////////////////////////////// -static void SC_color(float r, float g, float b, float a) { - GET_TLS(); - ProgramFragment *pf = (ProgramFragment *)rsc->getProgramFragment(); +void rsrColor(Context *rsc, Script *sc, float r, float g, float b, float a) { + ProgramFragment *pf = rsc->getProgramFragment(); pf->setConstantColor(rsc, r, g, b, a); } -static void SC_allocationSyncAll(RsAllocation va) { - CHECK_OBJ(va); - GET_TLS(); - static_cast<Allocation *>(va)->syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT); +void rsrFinish(Context *rsc, Script *sc) { + glFinish(); } -#if 0 -static void SC_allocationSyncAll2(RsAllocation va, RsAllocationUsageType source) { - CHECK_OBJ(va); - GET_TLS(); - static_cast<Allocation *>(va)->syncAll(rsc, source); -} -#endif -static void SC_ClearColor(float r, float g, float b, float a) { - GET_TLS(); +void rsrClearColor(Context *rsc, Script *sc, float r, float g, float b, float a) { + rsc->mFBOCache.setup(rsc); rsc->setupProgramStore(); glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); } -static void SC_ClearDepth(float v) { - GET_TLS(); +void rsrClearDepth(Context *rsc, Script *sc, float v) { + rsc->mFBOCache.setup(rsc); rsc->setupProgramStore(); glClearDepthf(v); glClear(GL_DEPTH_BUFFER_BIT); } -static uint32_t SC_getWidth() { - GET_TLS(); +uint32_t rsrGetWidth(Context *rsc, Script *sc) { return rsc->getWidth(); } -static uint32_t SC_getHeight() { - GET_TLS(); +uint32_t rsrGetHeight(Context *rsc, Script *sc) { return rsc->getHeight(); } -static void SC_DrawTextAlloc(RsAllocation va, int x, int y) { - CHECK_OBJ(va); - GET_TLS(); - Allocation *alloc = static_cast<Allocation *>(va); - const char *text = (const char *)alloc->getPtr(); - size_t allocSize = alloc->getType()->getSizeBytes(); +void rsrDrawTextAlloc(Context *rsc, Script *sc, Allocation *a, int x, int y) { + const char *text = (const char *)a->getPtr(); + size_t allocSize = a->getType()->getSizeBytes(); rsc->mStateFont.renderText(text, allocSize, x, y); } -static void SC_DrawText(const char *text, int x, int y) { - GET_TLS(); +void rsrDrawText(Context *rsc, Script *sc, const char *text, int x, int y) { size_t textLen = strlen(text); rsc->mStateFont.renderText(text, textLen, x, y); } -static void SC_setMetrics(Font::Rect *metrics, - int32_t *left, int32_t *right, - int32_t *top, int32_t *bottom) { +static void SetMetrics(Font::Rect *metrics, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { if (left) { *left = metrics->left; } @@ -347,118 +300,32 @@ static void SC_setMetrics(Font::Rect *metrics, } } -static void SC_MeasureTextAlloc(RsAllocation va, - int32_t *left, int32_t *right, - int32_t *top, int32_t *bottom) { - CHECK_OBJ(va); - GET_TLS(); - Allocation *alloc = static_cast<Allocation *>(va); - const char *text = (const char *)alloc->getPtr(); - size_t textLen = alloc->getType()->getSizeBytes(); +void rsrMeasureTextAlloc(Context *rsc, Script *sc, Allocation *a, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { + CHECK_OBJ(a); + const char *text = (const char *)a->getPtr(); + size_t textLen = a->getType()->getSizeBytes(); Font::Rect metrics; rsc->mStateFont.measureText(text, textLen, &metrics); - SC_setMetrics(&metrics, left, right, top, bottom); + SetMetrics(&metrics, left, right, top, bottom); } -static void SC_MeasureText(const char *text, - int32_t *left, int32_t *right, - int32_t *top, int32_t *bottom) { - GET_TLS(); +void rsrMeasureText(Context *rsc, Script *sc, const char *text, + int32_t *left, int32_t *right, int32_t *top, int32_t *bottom) { size_t textLen = strlen(text); Font::Rect metrics; rsc->mStateFont.measureText(text, textLen, &metrics); - SC_setMetrics(&metrics, left, right, top, bottom); + SetMetrics(&metrics, left, right, top, bottom); } -static void SC_BindFont(RsFont font) { +void rsrBindFont(Context *rsc, Script *sc, Font *font) { CHECK_OBJ(font); - GET_TLS(); rsi_ContextBindFont(rsc, font); } -static void SC_FontColor(float r, float g, float b, float a) { - GET_TLS(); +void rsrFontColor(Context *rsc, Script *sc, float r, float g, float b, float a) { rsc->mStateFont.setFontColor(r, g, b, a); } -////////////////////////////////////////////////////////////////////////////// -// Class implementation -////////////////////////////////////////////////////////////////////////////// - -// llvm name mangling ref -// <builtin-type> ::= v # void -// ::= b # bool -// ::= c # char -// ::= a # signed char -// ::= h # unsigned char -// ::= s # short -// ::= t # unsigned short -// ::= i # int -// ::= j # unsigned int -// ::= l # long -// ::= m # unsigned long -// ::= x # long long, __int64 -// ::= y # unsigned long long, __int64 -// ::= f # float -// ::= d # double - -static ScriptCState::SymbolTable_t gSyms[] = { - { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment, false }, - { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore, false }, - { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex, false }, - { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster, false }, - { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler, false }, - { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture, false }, - - { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix, false }, - { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix, false }, - { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix, false }, - - { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix, false }, - - { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor, false }, - - { "_Z11rsgGetWidthv", (void *)&SC_getWidth, false }, - { "_Z12rsgGetHeightv", (void *)&SC_getHeight, false }, - - { "_Z20rsgAllocationSyncAll13rs_allocation", (void *)&SC_allocationSyncAll, false }, - - { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect, false }, - { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad, false }, - { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords, false }, - { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace, false }, - - { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh, false }, - { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive, false }, - { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange, false }, - { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox, false }, - - { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false }, - { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false }, - - { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false }, - { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false }, - { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false }, - { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false }, - - { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false }, - { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false }, - - // misc - { "_Z5colorffff", (void *)&SC_color, false }, - - { NULL, NULL, false } -}; - -const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolGL(const char *sym) { - ScriptCState::SymbolTable_t *syms = gSyms; - - while (syms->mPtr) { - if (!strcmp(syms->mName, sym)) { - return syms; - } - syms++; - } - return NULL; } - +} diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 6cf07de..ab164c3 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -23,16 +23,96 @@ using namespace android::renderscript; ThreadIO::ThreadIO() { mToCore.init(16 * 1024); - mToClient.init(1024); } ThreadIO::~ThreadIO() { } +void ThreadIO::init(bool useSocket) { + mUsingSocket = useSocket; + + if (mUsingSocket) { + mToClientSocket.init(); + mToCoreSocket.init(); + } else { + mToClient.init(1024); + } +} + void ThreadIO::shutdown() { + //LOGE("shutdown 1"); mToCore.shutdown(); + //LOGE("shutdown 2"); } +void ThreadIO::coreFlush() { + //LOGE("coreFlush 1"); + if (mUsingSocket) { + } else { + mToCore.flush(); + } + //LOGE("coreFlush 2"); +} + +void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) { + //LOGE("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; + } + //LOGE("coreHeader ret %p", mCoreDataPtr); + return mCoreDataPtr; +} + +void ThreadIO::coreData(const void *data, size_t dataLen) { + //LOGE("coreData %p %i", data, dataLen); + mToCoreSocket.writeAsync(data, dataLen); + //LOGE("coreData ret %p", mCoreDataPtr); +} + +void ThreadIO::coreCommit() { + //LOGE("coreCommit %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize); + if (mUsingSocket) { + } else { + rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize); + mToCore.commit(mCoreCommandID, mCoreCommandSize); + } + //LOGE("coreCommit ret"); +} + +void ThreadIO::coreCommitSync() { + //LOGE("coreCommitSync %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize); + if (mUsingSocket) { + } else { + rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize); + mToCore.commitSync(mCoreCommandID, mCoreCommandSize); + } + //LOGE("coreCommitSync ret"); +} + +void ThreadIO::clientShutdown() { + //LOGE("coreShutdown 1"); + mToClient.shutdown(); + //LOGE("coreShutdown 2"); +} + +void ThreadIO::coreSetReturn(const void *data, size_t dataLen) { + rsAssert(dataLen <= sizeof(mToCoreRet)); + memcpy(&mToCoreRet, data, dataLen); +} + +void ThreadIO::coreGetReturn(void *data, size_t dataLen) { + memcpy(data, &mToCoreRet, dataLen); +} + + bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) { bool ret = false; while (!mToCore.isEmpty() || waitForCommand) { @@ -58,10 +138,88 @@ bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) { LOGE("playCoreCommands error con %p, cmd %i", con, cmdID); mToCore.printDebugData(); } - gPlaybackFuncs[cmdID](con, data); + 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; + } + } + receiveLen[0] = mLastClientHeader.bytes; + usrID[0] = mLastClientHeader.userID; + return (RsMessageToClientType)mLastClientHeader.cmdID; +} + +RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen, + uint32_t *usrID, size_t bufferLen) { + 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); + //LOGE("getMessageToClient 3 %i %i", commandID, bytesData); + //LOGE("getMessageToClient %i %i", commandID, *subID); + if (bufferLen >= receiveLen[0]) { + memcpy(data, d+1, receiveLen[0]); + mToClient.next(); + return (RsMessageToClientType)commandID; + } + } + return RS_MESSAGE_TO_CLIENT_RESIZE; +} + +bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data, + size_t dataLen, bool waitForSpace) { + 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; + } + } + + //LOGE("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)); + //LOGE("sendMessageToClient 3"); + return true; + } + return false; +} diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h index f9d0de7..cad7318 100644 --- a/libs/rs/rsThreadIO.h +++ b/libs/rs/rsThreadIO.h @@ -19,6 +19,7 @@ #include "rsUtils.h" #include "rsLocklessFifo.h" +#include "rsFifoSocket.h" // --------------------------------------------------------------------------- namespace android { @@ -31,17 +32,58 @@ public: ThreadIO(); ~ThreadIO(); + void init(bool useSocket = false); void shutdown(); // Plays back commands from the client. // Returns true if any commands were processed. bool playCoreCommands(Context *con, bool waitForCommand); + //LocklessCommandFifo mToCore; - LocklessCommandFifo mToCore; + + + 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); + + + RsMessageToClientType getClientHeader(size_t *receiveLen, uint32_t *usrID); + RsMessageToClientType getClientPayload(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen); + bool sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data, size_t dataLen, bool waitForSpace); + void clientShutdown(); + + +protected: + typedef struct CoreCmdHeaderRec { + uint32_t cmdID; + uint32_t bytes; + } CoreCmdHeader; + typedef struct ClientCmdHeaderRec { + uint32_t cmdID; + uint32_t bytes; + uint32_t userID; + } ClientCmdHeader; + ClientCmdHeader mLastClientHeader; + + size_t mCoreCommandSize; + uint32_t mCoreCommandID; + uint8_t * mCoreDataPtr; + uint8_t * mCoreDataBasePtr; + + bool mUsingSocket; LocklessCommandFifo mToClient; + LocklessCommandFifo mToCore; + + FifoSocket mToClientSocket; + FifoSocket mToCoreSocket; intptr_t mToCoreRet; + }; diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp index cd2be94..10e3182 100644 --- a/libs/rs/rsType.cpp +++ b/libs/rs/rsType.cpp @@ -274,17 +274,16 @@ Type * Type::cloneAndResize2D(Context *rsc, namespace android { namespace renderscript { -} -} - -RsType rsaTypeCreate(RsContext con, RsElement _e, uint32_t dimX, +RsType rsi_TypeCreate(Context *rsc, RsElement _e, uint32_t dimX, uint32_t dimY, uint32_t dimZ, bool mips, bool faces) { - Context *rsc = static_cast<Context *>(con); Element *e = static_cast<Element *>(_e); return Type::getType(rsc, e, dimX, dimY, dimZ, mips, faces); } +} +} + void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) { rsAssert(typeDataSize == 6); // Pack the data in the follofing way mDimX; mDimY; mDimZ; diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h index 90ae039..086db33 100644 --- a/libs/rs/rsType.h +++ b/libs/rs/rsType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -18,7 +18,6 @@ #define ANDROID_STRUCTURED_TYPE_H #include "rsElement.h" -#include "rsVertexArray.h" // --------------------------------------------------------------------------- namespace android { diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h index 3b60af5..3a6c85a 100644 --- a/libs/rs/rsUtils.h +++ b/libs/rs/rsUtils.h @@ -32,10 +32,6 @@ #include <time.h> #include <cutils/atomic.h> -#ifndef ANDROID_RS_SERIALIZE -#include <EGL/egl.h> -#endif - #include <math.h> #include "RenderScript.h" diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h new file mode 100644 index 0000000..7bb09bb --- /dev/null +++ b/libs/rs/rs_hal.h @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#ifndef RS_HAL_H +#define RS_HAL_H + +#include <RenderScriptDefines.h> + +namespace android { +namespace renderscript { + +class Context; +class ObjectBase; +class Element; +class Type; +class Allocation; +class Script; +class ScriptC; +class Program; +class ProgramStore; +class ProgramRaster; +class ProgramVertex; +class ProgramFragment; +class Mesh; +class Sampler; +class FBOCache; + +typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName); + +/** + * Script management functions + */ +typedef struct { + bool (*initGraphics)(const Context *); + void (*shutdownGraphics)(const Context *); + bool (*setSurface)(const Context *, uint32_t w, uint32_t h, RsNativeWindow); + void (*swap)(const Context *); + + void (*shutdownDriver)(Context *); + void (*getVersion)(unsigned int *major, unsigned int *minor); + void (*setPriority)(const Context *, int32_t priority); + + + + struct { + bool (*init)(const Context *rsc, ScriptC *s, + char const *resName, + char const *cacheDir, + uint8_t const *bitcode, + size_t bitcodeSize, + uint32_t flags); + + void (*invokeFunction)(const Context *rsc, Script *s, + uint32_t slot, + const void *params, + size_t paramLength); + int (*invokeRoot)(const Context *rsc, Script *s); + void (*invokeForEach)(const Context *rsc, + Script *s, + const Allocation * ain, + Allocation * aout, + const void * usr, + uint32_t usrLen, + const RsScriptCall *sc); + void (*invokeInit)(const Context *rsc, Script *s); + + void (*setGlobalVar)(const Context *rsc, const Script *s, + uint32_t slot, + void *data, + size_t dataLength); + void (*setGlobalBind)(const Context *rsc, const Script *s, + uint32_t slot, + void *data); + void (*setGlobalObj)(const Context *rsc, const Script *s, + uint32_t slot, + ObjectBase *data); + + void (*destroy)(const Context *rsc, Script *s); + } script; + + struct { + bool (*init)(const Context *rsc, Allocation *alloc, bool forceZero); + void (*destroy)(const Context *rsc, Allocation *alloc); + + void (*resize)(const Context *rsc, const Allocation *alloc, const Type *newType, + bool zeroNew); + void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src); + void (*markDirty)(const Context *rsc, const Allocation *alloc); + + void (*data1D)(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t lod, uint32_t count, + const void *data, uint32_t sizeBytes); + void (*data2D)(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, + RsAllocationCubemapFace face, uint32_t w, uint32_t h, + const void *data, uint32_t sizeBytes); + void (*data3D)(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, RsAllocationCubemapFace face, + uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); + + void (*elementData1D)(const Context *rsc, const Allocation *alloc, uint32_t x, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + void (*elementData2D)(const Context *rsc, const Allocation *alloc, uint32_t x, uint32_t y, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + + + } allocation; + + struct { + bool (*init)(const Context *rsc, const ProgramStore *ps); + void (*setActive)(const Context *rsc, const ProgramStore *ps); + void (*destroy)(const Context *rsc, const ProgramStore *ps); + } store; + + struct { + bool (*init)(const Context *rsc, const ProgramRaster *ps); + void (*setActive)(const Context *rsc, const ProgramRaster *ps); + void (*destroy)(const Context *rsc, const ProgramRaster *ps); + } raster; + + struct { + bool (*init)(const Context *rsc, const ProgramVertex *pv, + const char* shader, uint32_t shaderLen); + void (*setActive)(const Context *rsc, const ProgramVertex *pv); + void (*destroy)(const Context *rsc, const ProgramVertex *pv); + } vertex; + + struct { + bool (*init)(const Context *rsc, const ProgramFragment *pf, + const char* shader, uint32_t shaderLen); + void (*setActive)(const Context *rsc, const ProgramFragment *pf); + void (*destroy)(const Context *rsc, const ProgramFragment *pf); + } fragment; + + struct { + bool (*init)(const Context *rsc, const Mesh *m); + void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len); + void (*destroy)(const Context *rsc, const Mesh *m); + } mesh; + + struct { + bool (*init)(const Context *rsc, const Sampler *m); + void (*destroy)(const Context *rsc, const Sampler *m); + } sampler; + + struct { + bool (*init)(const Context *rsc, const FBOCache *fb); + void (*setActive)(const Context *rsc, const FBOCache *fb); + void (*destroy)(const Context *rsc, const FBOCache *fb); + } framebuffer; + +} RsdHalFunctions; + + +} +} + + +bool rsdHalInit(android::renderscript::Context *, uint32_t version_major, uint32_t version_minor); + +#endif + diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 4ac5b7f..b3f6c55 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -4,7 +4,7 @@ void printFileHeader(FILE *f) { fprintf(f, "/*\n"); - fprintf(f, " * Copyright (C) 2010 The Android Open Source Project\n"); + fprintf(f, " * Copyright (C) 2011 The Android Open Source Project\n"); fprintf(f, " *\n"); fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"); fprintf(f, " * you may not use this file except in compliance with the License.\n"); @@ -53,6 +53,10 @@ void printVarType(FILE *f, const VarType *vt) { fprintf(f, "*"); } } +} + +void printVarTypeAndName(FILE *f, const VarType *vt) { + printVarType(f, vt); if (vt->name[0]) { fprintf(f, " %s", vt->name); @@ -65,7 +69,7 @@ void printArgList(FILE *f, const ApiEntry * api, int assumePrevious) { if (ct || assumePrevious) { fprintf(f, ", "); } - printVarType(f, &api->params[ct]); + printVarTypeAndName(f, &api->params[ct]); } } @@ -86,41 +90,96 @@ void printStructures(FILE *f) { for (ct2=0; ct2 < api->paramCount; ct2++) { fprintf(f, " "); - printVarType(f, &api->params[ct2]); + printVarTypeAndName(f, &api->params[ct2]); fprintf(f, ";\n"); } fprintf(f, "};\n\n"); } } -void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext) { - printVarType(f, &api->ret); - fprintf(f, " %s%s (", prefix, api->name); - if (addContext) { - fprintf(f, "Context *"); +void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext, int isFnPtr) { + printVarTypeAndName(f, &api->ret); + if (isFnPtr) { + char t[1024]; + strcpy(t, api->name); + if (strlen(prefix) == 0) { + if (t[0] > 'A' && t[0] < 'Z') { + t[0] -= 'A' - 'a'; + } + } + fprintf(f, " (* %s%s) (", prefix, api->name); } else { - fprintf(f, "RsContext rsc"); + fprintf(f, " %s%s (", prefix, api->name); } - printArgList(f, api, 1); + if (!api->nocontext) { + if (addContext) { + fprintf(f, "Context *"); + } else { + fprintf(f, "RsContext rsc"); + } + } + printArgList(f, api, !api->nocontext); fprintf(f, ")"); } void printFuncDecls(FILE *f, const char *prefix, int addContext) { int ct; for (ct=0; ct < apiCount; ct++) { - printFuncDecl(f, &apis[ct], prefix, addContext); + printFuncDecl(f, &apis[ct], prefix, addContext, 0); fprintf(f, ";\n"); } fprintf(f, "\n\n"); } +void printFuncPointers(FILE *f, int addContext) { + fprintf(f, "\n"); + fprintf(f, "typedef struct RsApiEntrypoints {\n"); + int ct; + for (ct=0; ct < apiCount; ct++) { + fprintf(f, " "); + printFuncDecl(f, &apis[ct], "", addContext, 1); + fprintf(f, ";\n"); + } + fprintf(f, "} RsApiEntrypoints_t;\n\n"); +} + void printPlaybackFuncs(FILE *f, const char *prefix) { int ct; for (ct=0; ct < apiCount; ct++) { + if (apis[ct].direct) { + continue; + } + fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name); } } +static int hasInlineDataPointers(const ApiEntry * api) { + int ret = 0; + int ct; + if (api->sync || api->ret.typeName[0]) { + return 0; + } + for (ct=0; ct < api->paramCount; ct++) { + const VarType *vt = &api->params[ct]; + + if (!vt->isConst && vt->ptrLevel) { + // Non-const pointers cannot be inlined. + return 0; + } + if (vt->ptrLevel > 1) { + // not handled yet. + return 0; + } + + if (vt->isConst && vt->ptrLevel) { + // Non-const pointers cannot be inlined. + ret = 1; + } + } + return ret; +} + void printApiCpp(FILE *f) { int ct; int ct2; @@ -130,54 +189,233 @@ void printApiCpp(FILE *f) { fprintf(f, "#include \"rsThreadIO.h\"\n"); //fprintf(f, "#include \"rsgApiStructs.h\"\n"); fprintf(f, "#include \"rsgApiFuncDecl.h\"\n"); + fprintf(f, "#include \"rsFifo.h\"\n"); fprintf(f, "\n"); fprintf(f, "using namespace android;\n"); fprintf(f, "using namespace android::renderscript;\n"); - fprintf(f, "#include \"rsHandcode.h\"\n"); fprintf(f, "\n"); + printFuncPointers(f, 0); + + // Generate RS funcs for local fifo for (ct=0; ct < apiCount; ct++) { int needFlush = 0; const ApiEntry * api = &apis[ct]; - printFuncDecl(f, api, "rs", 0); + fprintf(f, "static "); + printFuncDecl(f, api, "LF_", 0, 0); fprintf(f, "\n{\n"); - if (api->handcodeApi) { - fprintf(f, " rsHCAPI_%s(rsc", api->name); + if (api->direct) { + fprintf(f, " "); + if (api->ret.typeName[0]) { + fprintf(f, "return "); + } + fprintf(f, "rsi_%s(", api->name); + if (!api->nocontext) { + fprintf(f, "(Context *)rsc"); + } for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; - fprintf(f, ", %s", vt->name); + if (ct2 > 0 || !api->nocontext) { + fprintf(f, ", "); + } + fprintf(f, "%s", vt->name); } fprintf(f, ");\n"); } else { fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n"); + fprintf(f, " const uint32_t size = sizeof(RS_CMD_%s);\n", api->name); + if (hasInlineDataPointers(api)) { + fprintf(f, " uint32_t dataSize = 0;\n"); + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->isConst && vt->ptrLevel) { + fprintf(f, " dataSize += %s_length;\n", vt->name); + } + } + } + //fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name); - fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name); - fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name); + if (hasInlineDataPointers(api)) { + fprintf(f, " RS_CMD_%s *cmd = NULL;\n", api->name); + fprintf(f, " if (dataSize < 1024) {;\n"); + fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name); + fprintf(f, " } else {\n"); + fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name); + fprintf(f, " }\n"); + fprintf(f, " uint8_t *payload = (uint8_t *)&cmd[1];\n"); + } else { + fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name, api->name); + } for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; needFlush += vt->ptrLevel; - fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name); + if (vt->ptrLevel && hasInlineDataPointers(api)) { + fprintf(f, " if (dataSize < 1024) {\n"); + 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 += %s_length;\n", vt->name); + fprintf(f, " } else {\n"); + fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name); + fprintf(f, " }\n"); + + } else { + fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name); + } } - if (api->ret.typeName[0]) { + if (api->ret.typeName[0] || api->sync) { needFlush = 1; } - fprintf(f, " io->mToCore.commit"); - if (needFlush) { - fprintf(f, "Sync"); + 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, " }\n"); + } else { + fprintf(f, " io->coreCommit"); + if (needFlush) { + fprintf(f, "Sync"); + } + fprintf(f, "();\n"); } - fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name); if (api->ret.typeName[0]) { - fprintf(f, " return reinterpret_cast<"); + fprintf(f, "\n "); printVarType(f, &api->ret); - fprintf(f, ">(io->mToCoreRet);\n"); + fprintf(f, " ret;\n"); + fprintf(f, " io->coreGetReturn(&ret, sizeof(ret));\n"); + fprintf(f, " return ret;\n"); } } fprintf(f, "};\n\n"); + + + fprintf(f, "static "); + printFuncDecl(f, api, "RF_", 0, 0); + fprintf(f, "\n{\n"); + fprintf(f, " Fifo *f = NULL;\n"); + fprintf(f, " RS_CMD_%s cmd;\n", api->name); + fprintf(f, " const uint32_t cmdSize = sizeof(cmd);\n"); + fprintf(f, " const uint32_t cmdID = RS_CMD_ID_%s;\n", api->name); + fprintf(f, " f->writeAsync(&cmdID, sizeof(cmdID));\n"); + fprintf(f, " intptr_t offset = cmdSize;\n"); + fprintf(f, " uint32_t dataSize = 0;\n"); + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->isConst && vt->ptrLevel) { + switch(vt->ptrLevel) { + case 1: + fprintf(f, " dataSize += %s_length;\n", vt->name); + break; + case 2: + fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " dataSize += %s_length[ct];\n", vt->name); + fprintf(f, " }\n"); + break; + default: + printf("pointer level not handled!!"); + } + } + } + fprintf(f, "\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + switch(vt->ptrLevel) { + case 0: + fprintf(f, " cmd.%s = %s;\n", vt->name, vt->name); + break; + case 1: + fprintf(f, " cmd.%s = (", vt->name); + printVarType(f, vt); + fprintf(f, ")offset;\n"); + fprintf(f, " offset += %s_length;\n", vt->name); + break; + case 2: + fprintf(f, " cmd.%s = (", vt->name); + printVarType(f, vt); + fprintf(f, ")offset;\n"); + fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " offset += %s_length[ct];\n", vt->name); + fprintf(f, " }\n"); + break; + default: + fprintf(stderr, "pointer level not handled!!"); + } + } + fprintf(f, "\n"); + + fprintf(f, " f->writeAsync(&cmd, cmdSize);\n"); + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->ptrLevel == 1) { + fprintf(f, " f->writeAsync(%s, %s_length);\n", vt->name, vt->name); + } + if (vt->ptrLevel == 2) { + fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name); + fprintf(f, " offset += %s_length[ct];\n", vt->name); + fprintf(f, " }\n"); + } + } + + if (api->ret.typeName[0]) { + fprintf(f, " "); + printVarType(f, &api->ret); + fprintf(f, " retValue;\n"); + fprintf(f, " f->writeWaitReturn(&retValue, sizeof(retValue));\n"); + fprintf(f, " return retValue;\n"); + } + fprintf(f, "}\n\n"); + } + + fprintf(f, "\n"); + fprintf(f, "static RsApiEntrypoints_t s_LocalTable = {\n"); + for (ct=0; ct < apiCount; ct++) { + fprintf(f, " LF_%s,\n", apis[ct].name); + } + fprintf(f, "};\n"); + + fprintf(f, "\n"); + fprintf(f, "static RsApiEntrypoints_t s_RemoteTable = {\n"); + for (ct=0; ct < apiCount; ct++) { + fprintf(f, " RF_%s,\n", apis[ct].name); + } + fprintf(f, "};\n"); + + fprintf(f, "static RsApiEntrypoints_t *s_CurrentTable = &s_LocalTable;\n\n"); + for (ct=0; ct < apiCount; ct++) { + int needFlush = 0; + const ApiEntry * api = &apis[ct]; + + printFuncDecl(f, api, "rs", 0, 0); + fprintf(f, "\n{\n"); + fprintf(f, " "); + if (api->ret.typeName[0]) { + fprintf(f, "return "); + } + fprintf(f, "s_CurrentTable->%s(", api->name); + + if (!api->nocontext) { + fprintf(f, "(Context *)rsc"); + } + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (ct2 > 0 || !api->nocontext) { + fprintf(f, ", "); + } + fprintf(f, "%s", vt->name); + } + fprintf(f, ");\n"); + fprintf(f, "}\n\n"); } + } void printPlaybackCpp(FILE *f) { @@ -192,37 +430,111 @@ void printPlaybackCpp(FILE *f) { fprintf(f, "\n"); fprintf(f, "namespace android {\n"); fprintf(f, "namespace renderscript {\n"); - fprintf(f, "#include \"rsHandcode.h\"\n"); fprintf(f, "\n"); for (ct=0; ct < apiCount; ct++) { const ApiEntry * api = &apis[ct]; - fprintf(f, "void rsp_%s(Context *con, const void *vp)\n", api->name); - fprintf(f, "{\n"); - if (api->handcodePlay) { - fprintf(f, " rsHCPLAY_%s(con, vp);\n", api->name); - } else { - //fprintf(f, " LOGE(\"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); - fprintf(f, " "); - if (api->ret.typeName[0]) { - fprintf(f, "con->mIO.mToCoreRet = (intptr_t)"); + if (api->direct) { + continue; + } + + fprintf(f, "void rsp_%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name); + + //fprintf(f, " LOGE(\"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); + + fprintf(f, " "); + if (api->ret.typeName[0]) { + fprintf(f, "\n "); + printVarType(f, &api->ret); + fprintf(f, " ret = "); + } + 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); + } + fprintf(f, ");\n"); + + if (api->ret.typeName[0]) { + fprintf(f, " con->mIO.coreSetReturn(&ret, sizeof(ret));\n"); + } + + fprintf(f, "};\n\n"); + } + + for (ct=0; ct < apiCount; ct++) { + const ApiEntry * api = &apis[ct]; + + fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name); + + //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name); + fprintf(f, " RS_CMD_%s cmd;\n", api->name); + fprintf(f, " f->read(&cmd, sizeof(cmd));\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->ptrLevel == 1) { + fprintf(f, " cmd.%s = (", vt->name); + printVarType(f, vt); + fprintf(f, ")scratch;\n"); + fprintf(f, " f->read(scratch, cmd.%s_length);\n", vt->name); + fprintf(f, " scratch += cmd.%s_length;\n", vt->name); } - 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); + if (vt->ptrLevel == 2) { + fprintf(f, " size_t sum_%s = 0;\n", vt->name); + fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " ((size_t *)scratch)[ct] = cmd.%s_length[ct];\n", vt->name); + fprintf(f, " sum_%s += cmd.%s_length[ct];\n", vt->name, vt->name); + fprintf(f, " }\n"); + fprintf(f, " f->read(scratch, sum_%s);\n", vt->name); + fprintf(f, " scratch += sum_%s;\n", vt->name); } - fprintf(f, ");\n"); } + fprintf(f, "\n"); + + if (api->ret.typeName[0]) { + fprintf(f, " "); + printVarType(f, &api->ret); + fprintf(f, " ret =\n"); + } + + fprintf(f, " rsi_%s(", api->name); + if (!api->nocontext) { + fprintf(f, "con"); + } + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (ct2 > 0 || !api->nocontext) { + fprintf(f, ",\n"); + } + fprintf(f, " cmd.%s", vt->name); + } + fprintf(f, ");\n"); + + if (api->ret.typeName[0]) { + fprintf(f, " f->readReturn(&ret, sizeof(ret));\n"); + } + fprintf(f, "};\n\n"); } - fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1); + fprintf(f, "RsPlaybackLocalFunc gPlaybackFuncs[%i] = {\n", apiCount + 1); fprintf(f, " NULL,\n"); for (ct=0; ct < apiCount; ct++) { - fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); + if (apis[ct].direct) { + fprintf(f, " NULL,\n"); + } else { + fprintf(f, " %s%s,\n", "rsp_", apis[ct].name); + } + } + fprintf(f, "};\n"); + + fprintf(f, "RsPlaybackRemoteFunc gPlaybackRemoteFuncs[%i] = {\n", apiCount + 1); + fprintf(f, " NULL,\n"); + for (ct=0; ct < apiCount; ct++) { + fprintf(f, " %s%s,\n", "rspr_", apis[ct].name); } fprintf(f, "};\n"); @@ -230,6 +542,8 @@ void printPlaybackCpp(FILE *f) { fprintf(f, "};\n"); } +void yylex(); + int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]); @@ -258,14 +572,21 @@ int main(int argc, char **argv) { { fprintf(f, "\n"); fprintf(f, "#include \"rsContext.h\"\n"); + fprintf(f, "#include \"rsFifo.h\"\n"); fprintf(f, "\n"); fprintf(f, "namespace android {\n"); fprintf(f, "namespace renderscript {\n"); printStructures(f); printFuncDecls(f, "rsi_", 1); printPlaybackFuncs(f, "rsp_"); - fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n"); - fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[%i];\n", apiCount + 1); + fprintf(f, "\n\ntypedef struct RsPlaybackRemoteHeaderRec {\n"); + fprintf(f, " uint32_t command;\n"); + fprintf(f, " uint32_t size;\n"); + fprintf(f, "} RsPlaybackRemoteHeader;\n\n"); + fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n"); + fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, Fifo *, uint8_t *scratch, size_t scratchSize);\n"); + fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1); + fprintf(f, "extern RsPlaybackRemoteFunc gPlaybackRemoteFuncs[%i];\n", apiCount + 1); fprintf(f, "}\n"); fprintf(f, "}\n"); @@ -290,6 +611,19 @@ int main(int argc, char **argv) { printPlaybackCpp(f); } break; + + case '4': // rsgApiStream.cpp + { + printFileHeader(f); + printPlaybackCpp(f); + } + + case '5': // rsgApiStreamReplay.cpp + { + printFileHeader(f); + printPlaybackCpp(f); + } + break; } fclose(f); return 0; diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh index 67ffc3d..d53bc95 100644 --- a/libs/rs/scriptc/rs_graphics.rsh +++ b/libs/rs/scriptc/rs_graphics.rsh @@ -1,6 +1,46 @@ #ifndef __RS_GRAPHICS_RSH__ #define __RS_GRAPHICS_RSH__ +/** + * Set the color target used for all subsequent rendering calls + * @param colorTarget + * @param slot + */ +extern void __attribute__((overloadable)) + rsgBindColorTarget(rs_allocation colorTarget, uint slot); + +/** + * Clear the previously set color target + * @param slot + */ +extern void __attribute__((overloadable)) + rsgClearColorTarget(uint slot); + +/** + * Set the depth target used for all subsequent rendering calls + * @param depthTarget + */ +extern void __attribute__((overloadable)) + rsgBindDepthTarget(rs_allocation depthTarget); + +/** + * Clear the previously set depth target + */ +extern void __attribute__((overloadable)) + rsgClearDepthTarget(void); + +/** + * Clear all color and depth targets and resume rendering into + * the framebuffer + */ +extern void __attribute__((overloadable)) + rsgClearAllRenderTargets(void); + +/** + * Force RenderScript to finish all rendering commands + */ +extern uint __attribute__((overloadable)) + rsgFinish(void); /** * Bind a new ProgramFragment to the rendering context. diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh index a010096..d9f4b4b 100644 --- a/libs/rs/scriptc/rs_types.rsh +++ b/libs/rs/scriptc/rs_types.rsh @@ -36,6 +36,10 @@ typedef float float2 __attribute__((ext_vector_type(2))); typedef float float3 __attribute__((ext_vector_type(3))); typedef float float4 __attribute__((ext_vector_type(4))); +typedef double double2 __attribute__((ext_vector_type(2))); +typedef double double3 __attribute__((ext_vector_type(3))); +typedef double double4 __attribute__((ext_vector_type(4))); + typedef uchar uchar2 __attribute__((ext_vector_type(2))); typedef uchar uchar3 __attribute__((ext_vector_type(3))); typedef uchar uchar4 __attribute__((ext_vector_type(4))); @@ -48,6 +52,10 @@ typedef uint uint2 __attribute__((ext_vector_type(2))); typedef uint uint3 __attribute__((ext_vector_type(3))); typedef uint uint4 __attribute__((ext_vector_type(4))); +typedef ulong ulong2 __attribute__((ext_vector_type(2))); +typedef ulong ulong3 __attribute__((ext_vector_type(3))); +typedef ulong ulong4 __attribute__((ext_vector_type(4))); + typedef char char2 __attribute__((ext_vector_type(2))); typedef char char3 __attribute__((ext_vector_type(3))); typedef char char4 __attribute__((ext_vector_type(4))); @@ -60,6 +68,9 @@ typedef int int2 __attribute__((ext_vector_type(2))); typedef int int3 __attribute__((ext_vector_type(3))); typedef int int4 __attribute__((ext_vector_type(4))); +typedef long long2 __attribute__((ext_vector_type(2))); +typedef long long3 __attribute__((ext_vector_type(3))); +typedef long long4 __attribute__((ext_vector_type(4))); typedef struct { float m[16]; diff --git a/libs/rs/spec.h b/libs/rs/spec.h index 82650a7..ecc5cc7 100644 --- a/libs/rs/spec.h +++ b/libs/rs/spec.h @@ -25,7 +25,8 @@ typedef struct { char name[256]; int sync; int handcodeApi; - int handcodePlay; + int direct; + int nocontext; int paramCount; VarType ret; VarType params[16]; diff --git a/libs/rs/spec.l b/libs/rs/spec.l index 6a9010fe..a24bfd3 100644 --- a/libs/rs/spec.l +++ b/libs/rs/spec.l @@ -20,6 +20,30 @@ ID [a-zA-Z_][a-zA-Z0-9_]* int typeNextState; + void checkPointerType() { + VarType *baseType = currType; + int curPtrLevel = 0; + while (curPtrLevel < baseType->ptrLevel) { + currType = &apis[apiCount].params[apis[apiCount].paramCount]; + currType->type = 4; + currType->ptrLevel = curPtrLevel; + if (currType->ptrLevel > 0) { + currType->isConst = 1; + } + sprintf(currType->typeName, "%s", "size_t"); + switch(baseType->ptrLevel - curPtrLevel) { + case 1: + sprintf(currType->name, "%s_length", baseType->name); + break; + case 2: + sprintf(currType->name, "%s_length_length", baseType->name); + break; + } + apis[apiCount].paramCount++; + curPtrLevel ++; + } + } + extern "C" int yylex(); %% @@ -31,6 +55,7 @@ ID [a-zA-Z_][a-zA-Z0-9_]* <comment>"*"+"/" BEGIN(INITIAL); <*>" " //printf("found ' '\n"); +<*>"\t" //printf("found ' '\n"); <*>"\n" ++num_lines; //printf("found lf \n"); {ID} { @@ -51,8 +76,12 @@ ID [a-zA-Z_][a-zA-Z0-9_]* apis[apiCount].handcodeApi = 1; } -<api_entry2>"handcodePlay" { - apis[apiCount].handcodePlay = 1; +<api_entry2>"direct" { + apis[apiCount].direct = 1; + } + +<api_entry2>"nocontext" { + apis[apiCount].nocontext = 1; } <api_entry2>"ret" { @@ -145,6 +174,7 @@ ID [a-zA-Z_][a-zA-Z0-9_]* <api_entry_param>{ID} { memcpy(currType->name, yytext, yyleng); + checkPointerType(); BEGIN(api_entry2); } diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index 4a0faf0..267e3edf 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -1,22 +1,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ - ISurfaceComposer.cpp \ - ISurface.cpp \ - ISurfaceComposerClient.cpp \ - IGraphicBufferAlloc.cpp \ - LayerState.cpp \ - SharedBufferStack.cpp \ - Surface.cpp \ - SurfaceComposerClient.cpp +LOCAL_SRC_FILES:= -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libhardware \ - libui +LOCAL_SHARED_LIBRARIES := LOCAL_MODULE:= libsurfaceflinger_client diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk deleted file mode 100644 index 212b8e7..0000000 --- a/libs/surfaceflinger_client/tests/Android.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -ifneq ($(TARGET_SIMULATOR),true) - -# Build the unit tests. -test_src_files := \ - Surface_test.cpp \ - -shared_libraries := \ - libcutils \ - libutils \ - libbinder \ - libsurfaceflinger_client \ - libstlport \ - -static_libraries := \ - libgtest \ - libgtest_main \ - -c_includes := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - -module_tags := tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_EXECUTABLE)) \ -) - -# Build the manual test programs. -include $(call all-subdir-makefiles) - -endif - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk deleted file mode 100644 index d3dfe04..0000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SharedBufferStackTest.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libsurfaceflinger_client - -LOCAL_MODULE:= test-sharedbufferstack - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp deleted file mode 100644 index 7ef5926..0000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#undef NDEBUG - -#include <assert.h> -#include <cutils/memory.h> -#include <cutils/log.h> -#include <utils/Errors.h> -#include <private/surfaceflinger/SharedBufferStack.h> - -using namespace android; - -void log(const char* prefix, int *b, size_t num); -void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); - -// ---------------------------------------------------------------------------- - -int main(int argc, char** argv) -{ - SharedClient client; - sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0)); - SharedBufferServer& s(*ps); - SharedBufferClient c(&client, 0, 4, 0); - - printf("basic test 0\n"); - int list0[4] = {0, 1, 2, 3}; - test0(s, c, 4, list0); - - printf("basic test 1\n"); - int list1[4] = {2, 1, 0, 3}; - test0(s, c, 4, list1); - - int b = c.dequeue(); - c.lock(b); - c.queue(b); - s.retireAndLock(); - - printf("basic test 2\n"); - int list2[4] = {1, 2, 3, 0}; - test0(s, c, 4, list2); - - - printf("resize test\n"); - class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { - SharedBufferServer& s; - virtual status_t operator()(int bufferCount) const { - return s.resize(bufferCount); - } - public: - SetBufferCountIPC(SharedBufferServer& s) : s(s) { } - } resize(s); - - c.setBufferCount(6, resize); - int list3[6] = {3, 2, 1, 4, 5, 0}; - test0(s, c, 6, list3); - - c.setBufferCount(4, resize); - int list4[4] = {1, 2, 3, 0}; - test0(s, c, 4, list4); - - return 0; -} - -void log(const char* prefix, int *b, size_t num) -{ - printf("%s: ", prefix); - for (size_t i=0 ; i<num ; i++) { - printf("%d ", b[i]); - } - printf("\n"); -} - -// ---------------------------------------------------------------------------- - -void test0( - SharedBufferServer& s, - SharedBufferClient& c, - size_t num, - int* list) -{ - status_t err; - int b[num], u[num], r[num]; - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==list[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - u[i] = b[num-2-i]; - } - u[num-1] = b[num-1]; - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(u[i]); - assert(err==0); - } - log(" Q", u, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - b[0] = c.dequeue(); - assert(b[0]==u[0]); - log("DQ", b, 1); - - c.undoDequeue(b[0]); - assert(err == 0); - log("UDQ", b, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - printf("\n"); -} diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index dc223f9..4393504 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -47,16 +47,16 @@ namespace android { class NativeBuffer : public EGLNativeBase< - android_native_buffer_t, + ANativeWindowBuffer, NativeBuffer, LightRefBase<NativeBuffer> > { public: NativeBuffer(int w, int h, int f, int u) : BASE() { - android_native_buffer_t::width = w; - android_native_buffer_t::height = h; - android_native_buffer_t::format = f; - android_native_buffer_t::usage = u; + ANativeWindowBuffer::width = w; + ANativeWindowBuffer::height = h; + ANativeWindowBuffer::format = f; + ANativeWindowBuffer::usage = u; } private: friend class LightRefBase<NativeBuffer>; @@ -201,7 +201,7 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const } int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, - android_native_buffer_t** buffer) + ANativeWindowBuffer** buffer) { FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); @@ -229,7 +229,7 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, } int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) + ANativeWindowBuffer* buffer) { FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); @@ -249,7 +249,7 @@ int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, } int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, - android_native_buffer_t* buffer) + ANativeWindowBuffer* buffer) { FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); @@ -270,10 +270,10 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, return res; } -int FramebufferNativeWindow::query(ANativeWindow* window, +int FramebufferNativeWindow::query(const ANativeWindow* window, int what, int* value) { - FramebufferNativeWindow* self = getSelf(window); + const FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); framebuffer_device_t* fb = self->fbDev; switch (what) { diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 97312a6..54a3ffa 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -33,7 +33,7 @@ namespace android { // =========================================================================== -// Buffer and implementation of android_native_buffer_t +// Buffer and implementation of ANativeWindowBuffer // =========================================================================== GraphicBuffer::GraphicBuffer() @@ -77,7 +77,7 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, handle = inHandle; } -GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership) +GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer) @@ -119,9 +119,9 @@ void GraphicBuffer::dumpAllocationsToSystemLog() GraphicBufferAllocator::dumpToSystemLog(); } -android_native_buffer_t* GraphicBuffer::getNativeBuffer() const +ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const { - return static_cast<android_native_buffer_t*>( + return static_cast<ANativeWindowBuffer*>( const_cast<GraphicBuffer*>(this)); } diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 1fc46aa..0af7f80 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -378,6 +378,19 @@ void PointerCoords::copyFrom(const PointerCoords& other) { } +// --- PointerProperties --- + +bool PointerProperties::operator==(const PointerProperties& other) const { + return id == other.id + && toolType == other.toolType; +} + +void PointerProperties::copyFrom(const PointerProperties& other) { + id = other.id; + toolType = other.toolType; +} + + // --- MotionEvent --- void MotionEvent::initialize( @@ -387,6 +400,7 @@ void MotionEvent::initialize( int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -394,20 +408,21 @@ void MotionEvent::initialize( nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; + mButtonState = buttonState; mXOffset = xOffset; mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; mDownTime = downTime; - mPointerIds.clear(); - mPointerIds.appendArray(pointerIds, pointerCount); + mPointerProperties.clear(); + mPointerProperties.appendArray(pointerProperties, pointerCount); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); @@ -419,12 +434,13 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; + mButtonState = other->mButtonState; mXOffset = other->mXOffset; mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; mDownTime = other->mDownTime; - mPointerIds = other->mPointerIds; + mPointerProperties = other->mPointerProperties; if (keepHistory) { mSampleEventTimes = other->mSampleEventTimes; @@ -489,9 +505,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { - size_t pointerCount = mPointerIds.size(); + size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { - if (mPointerIds.itemAt(i) == pointerId) { + if (mPointerProperties.itemAt(i).id == pointerId) { return i; } } @@ -588,21 +604,25 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); + mButtonState = parcel->readInt32(); mXOffset = parcel->readFloat(); mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); mDownTime = parcel->readInt64(); - mPointerIds.clear(); - mPointerIds.setCapacity(pointerCount); + mPointerProperties.clear(); + mPointerProperties.setCapacity(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.setCapacity(sampleCount); mSamplePointerCoords.clear(); mSamplePointerCoords.setCapacity(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { - mPointerIds.push(parcel->readInt32()); + mPointerProperties.push(); + PointerProperties& properties = mPointerProperties.editTop(); + properties.id = parcel->readInt32(); + properties.toolType = parcel->readInt32(); } while (sampleCount-- > 0) { @@ -619,7 +639,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { } status_t MotionEvent::writeToParcel(Parcel* parcel) const { - size_t pointerCount = mPointerIds.size(); + size_t pointerCount = mPointerProperties.size(); size_t sampleCount = mSampleEventTimes.size(); parcel->writeInt32(pointerCount); @@ -631,6 +651,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); + parcel->writeInt32(mButtonState); parcel->writeFloat(mXOffset); parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); @@ -638,7 +659,9 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { - parcel->writeInt32(mPointerIds.itemAt(i)); + const PointerProperties& properties = mPointerProperties.itemAt(i); + parcel->writeInt32(properties.id); + parcel->writeInt32(properties.toolType); } const PointerCoords* pc = mSamplePointerCoords.array(); @@ -732,7 +755,7 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Posi LOGD(" %d: position (%0.3f, %0.3f), vx=%0.3f, vy=%0.3f, speed=%0.3f", id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy)); } else { - assert(vx == 0 && vy == 0); + LOG_ASSERT(vx == 0 && vy == 0); LOGD(" %d: position (%0.3f, %0.3f), velocity not available", id, positions[index].x, positions[index].y); } diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 93d0d1f..ffdfe66 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -366,6 +366,7 @@ status_t InputPublisher::publishMotionEvent( int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -373,16 +374,17 @@ status_t InputPublisher::publishMotionEvent( nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, " + "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " + "xOffset=%f, yOffset=%f, " "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " "pointerCount=%d", mChannel->getName().string(), - deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset, - xPrecision, yPrecision, downTime, eventTime, pointerCount); + deviceId, source, action, flags, edgeFlags, metaState, buttonState, + xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif if (pointerCount > MAX_POINTERS || pointerCount < 1) { @@ -400,6 +402,7 @@ status_t InputPublisher::publishMotionEvent( mSharedMessage->motion.flags = flags; mSharedMessage->motion.edgeFlags = edgeFlags; mSharedMessage->motion.metaState = metaState; + mSharedMessage->motion.buttonState = buttonState; mSharedMessage->motion.xOffset = xOffset; mSharedMessage->motion.yOffset = yOffset; mSharedMessage->motion.xPrecision = xPrecision; @@ -411,7 +414,7 @@ status_t InputPublisher::publishMotionEvent( mSharedMessage->motion.sampleData[0].eventTime = eventTime; for (size_t i = 0; i < pointerCount; i++) { - mSharedMessage->motion.pointerIds[i] = pointerIds[i]; + mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]); mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); } @@ -694,6 +697,7 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { mSharedMessage->motion.flags, mSharedMessage->motion.edgeFlags, mSharedMessage->motion.metaState, + mSharedMessage->motion.buttonState, mSharedMessage->motion.xOffset, mSharedMessage->motion.yOffset, mSharedMessage->motion.xPrecision, @@ -701,7 +705,7 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { mSharedMessage->motion.downTime, mSharedMessage->motion.sampleData[0].eventTime, mSharedMessage->motion.pointerCount, - mSharedMessage->motion.pointerIds, + mSharedMessage->motion.pointerProperties, mSharedMessage->motion.sampleData[0].coords); size_t sampleCount = mSharedMessage->motion.sampleCount; diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp index b77489e..e48d5b7 100644 --- a/libs/ui/tests/InputEvent_test.cpp +++ b/libs/ui/tests/InputEvent_test.cpp @@ -232,7 +232,14 @@ const float MotionEventTest::X_OFFSET = 1.0f; const float MotionEventTest::Y_OFFSET = 1.1f; void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { - int32_t pointerIds[] = { 1, 2 }; + PointerProperties pointerProperties[2]; + pointerProperties[0].clear(); + pointerProperties[0].id = 1; + pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[1].clear(); + pointerProperties[1].id = 2; + pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + PointerCoords pointerCoords[2]; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); @@ -256,10 +263,10 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, - AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, + AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, - 2, pointerIds, pointerCoords); + 2, pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -311,6 +318,7 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); + ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState()); ASSERT_EQ(X_OFFSET, event->getXOffset()); ASSERT_EQ(Y_OFFSET, event->getYOffset()); ASSERT_EQ(2.0f, event->getXPrecision()); @@ -319,7 +327,9 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(2U, event->getPointerCount()); ASSERT_EQ(1, event->getPointerId(0)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0)); ASSERT_EQ(2, event->getPointerId(1)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1)); ASSERT_EQ(2U, event->getHistorySize()); @@ -534,19 +544,20 @@ TEST_F(MotionEventTest, Transform) { const float ROTATION = ARC * 2; const size_t pointerCount = 11; - int pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { float angle = float(i * ARC * PI_180); - pointerIds[i] = i; + pointerProperties[i].clear(); + pointerProperties[i].id = i; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, - 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index 6e18a4f..fcc4cad 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -156,13 +156,19 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; + const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY; const float xOffset = -10; const float yOffset = -20; const float xPrecision = 0.25; const float yPrecision = 0.5; const nsecs_t downTime = 3; const size_t pointerCount = 3; - const int32_t pointerIds[pointerCount] = { 2, 0, 1 }; + PointerProperties pointerProperties[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = (i + 2) % pointerCount; + pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + } Vector<nsecs_t> sampleEventTimes; Vector<PointerCoords> samplePointerCoords; @@ -186,8 +192,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( } status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags, - metaState, xOffset, yOffset, xPrecision, yPrecision, - downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array()); + metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, + downTime, sampleEventTimes[0], pointerCount, + pointerProperties, samplePointerCoords.array()); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -234,6 +241,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( EXPECT_EQ(flags, motionEvent->getFlags()); EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags()); EXPECT_EQ(metaState, motionEvent->getMetaState()); + EXPECT_EQ(buttonState, motionEvent->getButtonState()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(downTime, motionEvent->getDownTime()); @@ -243,7 +251,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( for (size_t i = 0; i < pointerCount; i++) { SCOPED_TRACE(i); - EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i)); + EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); + EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); } for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) { @@ -352,17 +361,20 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsErr ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = 1; - int32_t pointerIds[pointerCount] = { 0 }; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - pointerCoords[0].clear(); + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(INVALID_OPERATION, status) << "publisher publishMotionEvent should return INVALID_OPERATION because "; "the publisher was not reset"; @@ -373,11 +385,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = 0; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -387,11 +399,15 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS + 1; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -432,11 +448,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEven ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); status = mPublisher->appendMotionSample(0, pointerCoords); @@ -449,11 +469,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_Ret ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); status = mPublisher->sendDispatchSignal(); @@ -476,11 +500,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsE ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); for (int count = 1;; count++) { diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 0b4d1ac..22034c5 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -36,6 +36,7 @@ #include <dirent.h> #include <errno.h> #include <assert.h> +#include <strings.h> #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> @@ -1998,4 +1999,3 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } - diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index adb3174..f963058 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -20,12 +20,15 @@ #include <utils/ByteOrder.h> #include <stdio.h> +#include <string.h> #include <unistd.h> #include <cutils/log.h> namespace android { +static const bool DEBUG = false; + /* * File Format (v1): * @@ -75,6 +78,7 @@ BackupDataWriter::write_padding_for(int n) paddingSize = padding_extra(n); if (paddingSize > 0) { uint32_t padding = 0xbcbcbcbc; + if (DEBUG) LOGI("writing %d padding bytes for %d", paddingSize, n); amt = write(m_fd, &padding, paddingSize); if (amt != paddingSize) { m_status = errno; @@ -107,8 +111,8 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) } else { k = key; } - if (false) { - LOGD("Writing entity: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), key.string(), + if (DEBUG) { + LOGD("Writing header: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), key.string(), dataSize); } @@ -121,6 +125,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) header.keyLen = tolel(keyLen); header.dataSize = tolel(dataSize); + if (DEBUG) LOGI("writing entity header, %d bytes", sizeof(entity_header_v1)); amt = write(m_fd, &header, sizeof(entity_header_v1)); if (amt != sizeof(entity_header_v1)) { m_status = errno; @@ -128,6 +133,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) } m_pos += amt; + if (DEBUG) LOGI("writing entity header key, %d bytes", keyLen+1); amt = write(m_fd, k.string(), keyLen+1); if (amt != keyLen+1) { m_status = errno; @@ -145,7 +151,12 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) status_t BackupDataWriter::WriteEntityData(const void* data, size_t size) { + if (DEBUG) LOGD("Writing data: size=%lu", (unsigned long) size); + if (m_status != NO_ERROR) { + if (DEBUG) { + LOGD("Not writing data - stream in error state %d (%s)", m_status, strerror(m_status)); + } return m_status; } @@ -155,6 +166,7 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size) ssize_t amt = write(m_fd, data, size); if (amt != (ssize_t)size) { m_status = errno; + if (DEBUG) LOGD("write returned error %d (%s)", m_status, strerror(m_status)); return m_status; } m_pos += amt; diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp index 4ad9b51..87549fe 100644 --- a/libs/utils/BackupHelpers.cpp +++ b/libs/utils/BackupHelpers.cpp @@ -442,6 +442,278 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD return 0; } +// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of +// returning the initial dest, return a pointer to the trailing NUL. +static char* strcpy_ptr(char* dest, const char* str) { + if (dest && str) { + while ((*dest = *str) != 0) { + dest++; + str++; + } + } + return dest; +} + +static void calc_tar_checksum(char* buf) { + // [ 148 : 8 ] checksum -- to be calculated with this field as space chars + memset(buf + 148, ' ', 8); + + uint16_t sum = 0; + for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) { + sum += *p; + } + + // Now write the real checksum value: + // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC + sprintf(buf + 148, "%06o", sum); // the trailing space is already in place +} + +// Returns number of bytes written +static int write_pax_header_entry(char* buf, const char* key, const char* value) { + // start with the size of "1 key=value\n" + int len = strlen(key) + strlen(value) + 4; + if (len > 9) len++; + if (len > 99) len++; + if (len > 999) len++; + // since PATH_MAX is 4096 we don't expect to have to generate any single + // header entry longer than 9999 characters + + return sprintf(buf, "%d %s=%s\n", len, key, value); +} + +int write_tarfile(const String8& packageName, const String8& domain, + const String8& rootpath, const String8& filepath, BackupDataWriter* writer) +{ + // In the output stream everything is stored relative to the root + const char* relstart = filepath.string() + rootpath.length(); + if (*relstart == '/') relstart++; // won't be true when path == rootpath + String8 relpath(relstart); + + // If relpath is empty, it means this is the top of one of the standard named + // domain directories, so we should just skip it + if (relpath.length() == 0) { + return 0; + } + + // Too long a name for the ustar format? + // "apps/" + packagename + '/' + domainpath < 155 chars + // relpath < 100 chars + bool needExtended = false; + if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) { + needExtended = true; + } + + // Non-7bit-clean path also means needing pax extended format + if (!needExtended) { + for (size_t i = 0; i < filepath.length(); i++) { + if ((filepath[i] & 0x80) != 0) { + needExtended = true; + break; + } + } + } + + int err = 0; + struct stat64 s; + if (lstat64(filepath.string(), &s) != 0) { + err = errno; + LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string()); + return err; + } + + String8 fullname; // for pax later on + String8 prefix; + + const int isdir = S_ISDIR(s.st_mode); + if (isdir) s.st_size = 0; // directories get no actual data in the tar stream + + // !!! TODO: use mmap when possible to avoid churning the buffer cache + // !!! TODO: this will break with symlinks; need to use readlink(2) + int fd = open(filepath.string(), O_RDONLY); + if (fd < 0) { + err = errno; + LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string()); + return err; + } + + // read/write up to this much at a time. + const size_t BUFSIZE = 32 * 1024; + char* buf = new char[BUFSIZE]; + char* paxHeader = buf + 512; // use a different chunk of it as separate scratch + char* paxData = buf + 1024; + + if (buf == NULL) { + LOGE("Out of mem allocating transfer buffer"); + err = ENOMEM; + goto cleanup; + } + + // Good to go -- first construct the standard tar header at the start of the buffer + memset(buf, 0, BUFSIZE); + + // Magic fields for the ustar file format + strcat(buf + 257, "ustar"); + strcat(buf + 263, "00"); + + // [ 265 : 32 ] user name, ignored on restore + // [ 297 : 32 ] group name, ignored on restore + + // [ 100 : 8 ] file mode + snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT); + + // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time + // [ 116 : 8 ] gid -- ignored in Android format + snprintf(buf + 108, 8, "0%lo", s.st_uid); + snprintf(buf + 116, 8, "0%lo", s.st_gid); + + // [ 124 : 12 ] file size in bytes + if (s.st_size > 077777777777LL) { + // very large files need a pax extended size header + needExtended = true; + } + snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); + + // [ 136 : 12 ] last mod time as a UTC time_t + snprintf(buf + 136, 12, "%0lo", s.st_mtime); + + // [ 156 : 1 ] link/file type + uint8_t type; + if (isdir) { + type = '5'; // tar magic: '5' == directory + } else if (S_ISREG(s.st_mode)) { + type = '0'; // tar magic: '0' == normal file + } else { + LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string()); + goto cleanup; + } + buf[156] = type; + + // [ 157 : 100 ] name of linked file [not implemented] + + { + // Prefix and main relative path. Path lengths have been preflighted. + if (packageName.length() > 0) { + prefix = "apps/"; + prefix += packageName; + } + if (domain.length() > 0) { + prefix.appendPath(domain); + } + + // pax extended means we don't put in a prefix field, and put a different + // string in the basic name field. We can also construct the full path name + // out of the substrings we've now built. + fullname = prefix; + fullname.appendPath(relpath); + + // ustar: + // [ 0 : 100 ]; file name/path + // [ 345 : 155 ] filename path prefix + // We only use the prefix area if fullname won't fit in the path + if (fullname.length() > 100) { + strncpy(buf, relpath.string(), 100); + strncpy(buf + 345, prefix.string(), 155); + } else { + strncpy(buf, fullname.string(), 100); + } + } + + // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used + + LOGI(" Name: %s", fullname.string()); + + // If we're using a pax extended header, build & write that here; lengths are + // already preflighted + if (needExtended) { + char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal + char* p = paxData; + + // construct the pax extended header data block + memset(paxData, 0, BUFSIZE - (paxData - buf)); + int len; + + // size header -- calc len in digits by actually rendering the number + // to a string - brute force but simple + snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size); + p += write_pax_header_entry(p, "size", sizeStr); + + // fullname was generated above with the ustar paths + p += write_pax_header_entry(p, "path", fullname.string()); + + // Now we know how big the pax data is + int paxLen = p - paxData; + + // Now build the pax *header* templated on the ustar header + memcpy(paxHeader, buf, 512); + + String8 leaf = fullname.getPathLeaf(); + memset(paxHeader, 0, 100); // rewrite the name area + snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string()); + memset(paxHeader + 345, 0, 155); // rewrite the prefix area + strncpy(paxHeader + 345, prefix.string(), 155); + + paxHeader[156] = 'x'; // mark it as a pax extended header + + // [ 124 : 12 ] size of pax extended header data + memset(paxHeader + 124, 0, 12); + snprintf(paxHeader + 124, 12, "%011o", p - paxData); + + // Checksum and write the pax block header + calc_tar_checksum(paxHeader); + writer->WriteEntityData(paxHeader, 512); + + // Now write the pax data itself + int paxblocks = (paxLen + 511) / 512; + writer->WriteEntityData(paxData, 512 * paxblocks); + } + + // Checksum and write the 512-byte ustar file header block to the output + calc_tar_checksum(buf); + writer->WriteEntityData(buf, 512); + + // Now write the file data itself, for real files. We honor tar's convention that + // only full 512-byte blocks are sent to write(). + if (!isdir) { + off64_t toWrite = s.st_size; + while (toWrite > 0) { + size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE; + ssize_t nRead = read(fd, buf, toRead); + if (nRead < 0) { + err = errno; + LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(), + err, strerror(err)); + break; + } else if (nRead == 0) { + LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite, + filepath.string()); + err = EIO; + break; + } + + // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This + // depends on the OS guarantee that for ordinary files, read() will never return + // less than the number of bytes requested. + ssize_t partial = (nRead+512) % 512; + if (partial > 0) { + ssize_t remainder = 512 - partial; + memset(buf + nRead, 0, remainder); + nRead += remainder; + } + writer->WriteEntityData(buf, nRead); + toWrite -= nRead; + } + } + +cleanup: + delete [] buf; +done: + close(fd); + return err; +} +// end tarfile + + + #define RESTORE_BUF_SIZE (8*1024) RestoreHelperBase::RestoreHelperBase() |