diff options
Diffstat (limited to 'libs')
221 files changed, 25189 insertions, 5893 deletions
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 13dc500..f9d9f25 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -16,6 +16,7 @@ sources := \ Binder.cpp \ BpBinder.cpp \ + CursorWindow.cpp \ IInterface.cpp \ IMemory.cpp \ IPCThreadState.cpp \ diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp new file mode 100644 index 0000000..bdd4dd6 --- /dev/null +++ b/libs/binder/CursorWindow.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2006-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 LOG_TAG +#define LOG_TAG "CursorWindow" + +#include <utils/Log.h> +#include <binder/CursorWindow.h> +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryBase.h> + +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +namespace android { + +CursorWindow::CursorWindow(size_t maxSize) : + mMaxSize(maxSize) +{ +} + +bool CursorWindow::setMemory(const sp<IMemory>& memory) +{ + mMemory = memory; + mData = (uint8_t *) memory->pointer(); + if (mData == NULL) { + return false; + } + mHeader = (window_header_t *) mData; + + // Make the window read-only + ssize_t size = memory->size(); + mSize = size; + mMaxSize = size; + mFreeOffset = size; +LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData); + return true; +} + +bool CursorWindow::initBuffer(bool localOnly) +{ + //TODO Use a non-memory dealer mmap region for localOnly + + sp<MemoryHeapBase> heap; + heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow"); + if (heap != NULL) { + mMemory = new MemoryBase(heap, 0, mMaxSize); + if (mMemory != NULL) { + mData = (uint8_t *) mMemory->pointer(); + if (mData) { + mHeader = (window_header_t *) mData; + mSize = mMaxSize; + + // Put the window into a clean state + clear(); + LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData); + return true; + } + } + LOGE("CursorWindow heap allocation failed"); + return false; + } else { + LOGE("failed to create the CursorWindow heap"); + return false; + } +} + +CursorWindow::~CursorWindow() +{ + // Everything that matters is a smart pointer +} + +void CursorWindow::clear() +{ + mHeader->numRows = 0; + mHeader->numColumns = 0; + mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE; + // Mark the first chunk's next 'pointer' as null + *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0; +} + +int32_t CursorWindow::freeSpace() +{ + int32_t freeSpace = mSize - mFreeOffset; + if (freeSpace < 0) { + freeSpace = 0; + } + return freeSpace; +} + +field_slot_t * CursorWindow::allocRow() +{ + // Fill in the row slot + row_slot_t * rowSlot = allocRowSlot(); + if (rowSlot == NULL) { + return NULL; + } + + // Allocate the slots for the field directory + size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t); + uint32_t fieldDirOffset = alloc(fieldDirSize); + if (!fieldDirOffset) { + mHeader->numRows--; + LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows); + return NULL; + } + field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset); + memset(fieldDir, 0x0, fieldDirSize); + +LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset); + rowSlot->offset = fieldDirOffset; + + return fieldDir; +} + +uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned) +{ + int32_t size; + uint32_t padding; + if (aligned) { + // 4 byte alignment + padding = 4 - (mFreeOffset & 0x3); + } else { + padding = 0; + } + + size = requestedSize + padding; + + if (size > freeSpace()) { + LOGV("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size, + freeSpace(), mHeader->numRows); + // Only grow the window if the first row doesn't fit + if (mHeader->numRows > 1) { + LOGV("not growing since there are already %d row(s), max size %d", mHeader->numRows, + mMaxSize); + return 0; + } + + // Find a new size that will fit the allocation + int allocated = mSize - freeSpace(); + int newSize = mSize + WINDOW_ALLOCATION_SIZE; + while (size > (newSize - allocated)) { + newSize += WINDOW_ALLOCATION_SIZE; + if (newSize > mMaxSize) { + LOGE("Attempting to grow window beyond max size (%d)", mMaxSize); + return 0; + } + } +LOG_WINDOW("found size %d", newSize); + mSize = newSize; + } + + uint32_t offset = mFreeOffset + padding; + mFreeOffset += size; + return offset; +} + +row_slot_t * CursorWindow::getRowSlot(int row) +{ + LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row); + int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS; + int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS; + int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); + uint8_t * rowChunk = mData + sizeof(window_header_t); + for (int i = 0; i < chunkNum; i++) { + rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset))); + chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); + } + return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); + LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row); +} + +row_slot_t * CursorWindow::allocRowSlot() +{ + int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS; + int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS; + int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); + uint8_t * rowChunk = mData + sizeof(window_header_t); +LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos); + for (int i = 0; i < chunkNum; i++) { + uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset)); +LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset); + if (nextChunkOffset == 0) { + // Allocate a new row chunk + nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true); + if (nextChunkOffset == 0) { + return NULL; + } + rowChunk = offsetToPtr(nextChunkOffset); +LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk); + *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData; + // Mark the new chunk's next 'pointer' as null + *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0; + } else { +LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset); + rowChunk = offsetToPtr(nextChunkOffset); + chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); + } + } + mHeader->numRows++; + + return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); +} + +field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column) +{ + if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { + LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); + return NULL; + } + row_slot_t * rowSlot = getRowSlot(row); + if (!rowSlot) { + LOGE("Failed to find rowSlot for row %d", row); + return NULL; + } + if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { + LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); + return NULL; + } + int fieldDirOffset = rowSlot->offset; + return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; +} + +uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut) +{ + if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { + LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); + return -1; + } + row_slot_t * rowSlot = getRowSlot(row); + if (!rowSlot) { + LOGE("Failed to find rowSlot for row %d", row); + return -1; + } + if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { + LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); + return -1; + } +LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset); + field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset); +LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type); + + // Copy the data to the out param + slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset; + slotOut->data.buffer.size = fieldDir[column].data.buffer.size; + slotOut->type = fieldDir[column].type; + return 0; +} + +void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size) +{ + assert(offset + size <= mSize); + memcpy(mData + offset, data, size); +} + +void CursorWindow::copyIn(uint32_t offset, int64_t data) +{ + assert(offset + sizeof(int64_t) <= mSize); + memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t)); +} + +void CursorWindow::copyIn(uint32_t offset, double data) +{ + assert(offset + sizeof(double) <= mSize); + memcpy(mData + offset, (uint8_t *)&data, sizeof(double)); +} + +void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size) +{ + assert(offset + size <= mSize); + memcpy(data, mData + offset, size); +} + +int64_t CursorWindow::copyOutLong(uint32_t offset) +{ + int64_t value; + assert(offset + sizeof(int64_t) <= mSize); + memcpy(&value, mData + offset, sizeof(int64_t)); + return value; +} + +double CursorWindow::copyOutDouble(uint32_t offset) +{ + double value; + assert(offset + sizeof(double) <= mSize); + memcpy(&value, mData + offset, sizeof(double)); + return value; +} + +bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot) { + return false; + } + +#if WINDOW_STORAGE_INLINE_NUMERICS + fieldSlot->data.l = value; +#else + int offset = alloc(sizeof(int64_t)); + if (!offset) { + return false; + } + + copyIn(offset, value); + + fieldSlot->data.buffer.offset = offset; + fieldSlot->data.buffer.size = sizeof(int64_t); +#endif + fieldSlot->type = FIELD_TYPE_INTEGER; + return true; +} + +bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot) { + return false; + } + +#if WINDOW_STORAGE_INLINE_NUMERICS + fieldSlot->data.d = value; +#else + int offset = alloc(sizeof(int64_t)); + if (!offset) { + return false; + } + + copyIn(offset, value); + + fieldSlot->data.buffer.offset = offset; + fieldSlot->data.buffer.size = sizeof(double); +#endif + fieldSlot->type = FIELD_TYPE_FLOAT; + return true; +} + +bool CursorWindow::putNull(unsigned int row, unsigned int col) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot) { + return false; + } + + fieldSlot->type = FIELD_TYPE_NULL; + fieldSlot->data.buffer.offset = 0; + fieldSlot->data.buffer.size = 0; + return true; +} + +bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) { + return false; + } + +#if WINDOW_STORAGE_INLINE_NUMERICS + *valueOut = fieldSlot->data.l; +#else + *valueOut = copyOutLong(fieldSlot->data.buffer.offset); +#endif + return true; +} + +bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) { + return false; + } + +#if WINDOW_STORAGE_INLINE_NUMERICS + *valueOut = fieldSlot->data.d; +#else + *valueOut = copyOutDouble(fieldSlot->data.buffer.offset); +#endif + return true; +} + +bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut) +{ + field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); + if (!fieldSlot) { + return false; + } + + if (fieldSlot->type != FIELD_TYPE_NULL) { + *valueOut = false; + } else { + *valueOut = true; + } + return true; +} + +}; // namespace android diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index 7efc6d7..b5f78e8 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -167,32 +167,20 @@ status_t Camera::unlock() return c->unlock(); } -// pass the buffered ISurface to the camera service +// pass the buffered Surface to the camera service status_t Camera::setPreviewDisplay(const sp<Surface>& surface) { - LOGV("setPreviewDisplay"); + LOGV("setPreviewDisplay(%p)", surface.get()); sp <ICamera> c = mCamera; if (c == 0) return NO_INIT; if (surface != 0) { - return c->setPreviewDisplay(surface->getISurface()); + return c->setPreviewDisplay(surface); } else { LOGD("app passed NULL surface"); return c->setPreviewDisplay(0); } } -status_t Camera::setPreviewDisplay(const sp<ISurface>& surface) -{ - LOGV("setPreviewDisplay"); - if (surface == 0) { - LOGD("app passed NULL surface"); - } - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->setPreviewDisplay(surface); -} - - // start preview mode status_t Camera::startPreview() { @@ -375,4 +363,3 @@ void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) { } }; // namespace android - diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 83e5e57..45b1b9a 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -73,6 +73,8 @@ const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported"; const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported"; const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances"; const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format"; +const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size"; +const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values"; const char CameraParameters::TRUE[] = "true"; const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity"; @@ -129,7 +131,7 @@ const char CameraParameters::SCENE_MODE_PARTY[] = "party"; const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight"; const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode"; -// Formats for setPreviewFormat and setPictureFormat. +const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p"; const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp"; const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp"; const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv"; @@ -337,6 +339,27 @@ void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const parseSizesList(previewSizesStr, sizes); } +void CameraParameters::setVideoSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set(KEY_VIDEO_SIZE, str); +} + +void CameraParameters::getVideoSize(int *width, int *height) const +{ + *width = *height = -1; + const char *p = get(KEY_VIDEO_SIZE); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + +void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const +{ + const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES); + parseSizesList(videoSizesStr, sizes); +} + void CameraParameters::setPreviewFrameRate(int fps) { set(KEY_PREVIEW_FRAME_RATE, fps); diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp index 13673b5..94dc5c1 100644 --- a/libs/camera/ICamera.cpp +++ b/libs/camera/ICamera.cpp @@ -64,13 +64,13 @@ public: remote()->transact(DISCONNECT, data, &reply); } - // pass the buffered ISurface to the camera service - status_t setPreviewDisplay(const sp<ISurface>& surface) + // pass the buffered Surface to the camera service + status_t setPreviewDisplay(const sp<Surface>& surface) { LOGV("setPreviewDisplay"); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - data.writeStrongBinder(surface->asBinder()); + Surface::writeToParcel(surface, &data); remote()->transact(SET_PREVIEW_DISPLAY, data, &reply); return reply.readInt32(); } @@ -258,7 +258,7 @@ status_t BnCamera::onTransact( case SET_PREVIEW_DISPLAY: { LOGV("SET_PREVIEW_DISPLAY"); CHECK_INTERFACE(ICamera, data, reply); - sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder()); + sp<Surface> surface = Surface::readFromParcel(data); reply->writeInt32(setPreviewDisplay(surface)); return NO_ERROR; } break; @@ -376,4 +376,3 @@ status_t BnCamera::onTransact( // ---------------------------------------------------------------------------- }; // namespace android - diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk new file mode 100644 index 0000000..437a9ef --- /dev/null +++ b/libs/hwui/Android.mk @@ -0,0 +1,47 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# Only build libhwui when USE_OPENGL_RENDERER is +# defined in the current device/board configuration +ifeq ($(USE_OPENGL_RENDERER),true) + LOCAL_SRC_FILES:= \ + utils/SortedListImpl.cpp \ + DisplayListRenderer.cpp \ + FboCache.cpp \ + FontRenderer.cpp \ + GammaFontRenderer.cpp \ + GradientCache.cpp \ + LayerCache.cpp \ + Matrix.cpp \ + OpenGLDebugRenderer.cpp \ + OpenGLRenderer.cpp \ + Patch.cpp \ + PatchCache.cpp \ + PathCache.cpp \ + Program.cpp \ + ProgramCache.cpp \ + SkiaColorFilter.cpp \ + SkiaShader.cpp \ + TextureCache.cpp \ + TextDropShadowCache.cpp + + LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + $(LOCAL_PATH)/../../include/utils \ + external/skia/include/core \ + external/skia/include/effects \ + external/skia/include/images \ + external/skia/src/ports \ + external/skia/include/utils + + LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER + LOCAL_MODULE_CLASS := SHARED_LIBRARIES + LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia + LOCAL_MODULE := libhwui + LOCAL_MODULE_TAGS := optional + LOCAL_PRELINK_MODULE := false + + include $(BUILD_SHARED_LIBRARY) + + include $(call all-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h new file mode 100644 index 0000000..2952a66 --- /dev/null +++ b/libs/hwui/Caches.h @@ -0,0 +1,83 @@ +/* + * 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_UI_CACHES_H +#define ANDROID_UI_CACHES_H + +#ifndef LOG_TAG + #define LOG_TAG "OpenGLRenderer" +#endif + +#include <utils/Singleton.h> + +#include "TextureCache.h" +#include "LayerCache.h" +#include "GradientCache.h" +#include "PatchCache.h" +#include "GammaFontRenderer.h" +#include "ProgramCache.h" +#include "PathCache.h" +#include "TextDropShadowCache.h" +#include "FboCache.h" +#include "Line.h" + +namespace android { +namespace uirenderer { + +struct CacheLogger { + CacheLogger() { + LOGD("Creating caches"); + } +}; // struct CacheLogger + +class Caches: public Singleton<Caches> { + Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO), + lastDstMode(GL_ZERO), currentProgram(NULL) { + } + + friend class Singleton<Caches>; + + CacheLogger logger; + +public: + bool blend; + GLenum lastSrcMode; + GLenum lastDstMode; + Program* currentProgram; + + TextureCache textureCache; + LayerCache layerCache; + GradientCache gradientCache; + ProgramCache programCache; + PathCache pathCache; + PatchCache patchCache; + TextDropShadowCache dropShadowCache; + FboCache fboCache; + GammaFontRenderer fontRenderer; + + Line line; +}; // class Caches + +}; // namespace uirenderer + +#ifdef USE_OPENGL_RENDERER +using namespace uirenderer; +ANDROID_SINGLETON_STATIC_INSTANCE(Caches); +#endif + +}; // namespace android + +#endif // ANDROID_UI_CACHES_H diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp new file mode 100644 index 0000000..b3517c4 --- /dev/null +++ b/libs/hwui/DisplayListRenderer.cpp @@ -0,0 +1,588 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include "DisplayListRenderer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define PATH_HEAP_SIZE 64 + +/////////////////////////////////////////////////////////////////////////////// +// Helpers +/////////////////////////////////////////////////////////////////////////////// + +PathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { +} + +PathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { + int count = buffer.readS32(); + + mPaths.setCount(count); + SkPath** ptr = mPaths.begin(); + SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath)); + + for (int i = 0; i < count; i++) { + new (p) SkPath; + p->unflatten(buffer); + *ptr++ = p; + p++; + } +} + +PathHeap::~PathHeap() { + SkPath** iter = mPaths.begin(); + SkPath** stop = mPaths.end(); + while (iter < stop) { + (*iter)->~SkPath(); + iter++; + } +} + +int PathHeap::append(const SkPath& path) { + SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath)); + new (p) SkPath(path); + *mPaths.append() = p; + return mPaths.count(); +} + +void PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const { + int count = mPaths.count(); + + buffer.write32(count); + SkPath** iter = mPaths.begin(); + SkPath** stop = mPaths.end(); + while (iter < stop) { + (*iter)->flatten(buffer); + iter++; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Display list +/////////////////////////////////////////////////////////////////////////////// + +DisplayList::DisplayList(const DisplayListRenderer& recorder) { + const SkWriter32& writer = recorder.writeStream(); + init(); + + if (writer.size() == 0) { + return; + } + + size_t size = writer.size(); + void* buffer = sk_malloc_throw(size); + writer.flatten(buffer); + mReader.setMemory(buffer, size); + + mRCPlayback.reset(&recorder.mRCRecorder); + mRCPlayback.setupBuffer(mReader); + + mTFPlayback.reset(&recorder.mTFRecorder); + mTFPlayback.setupBuffer(mReader); + + const SkTDArray<const SkFlatBitmap*>& bitmaps = recorder.getBitmaps(); + mBitmapCount = bitmaps.count(); + if (mBitmapCount > 0) { + mBitmaps = new SkBitmap[mBitmapCount]; + for (const SkFlatBitmap** flatBitmapPtr = bitmaps.begin(); + flatBitmapPtr != bitmaps.end(); flatBitmapPtr++) { + const SkFlatBitmap* flatBitmap = *flatBitmapPtr; + int index = flatBitmap->index() - 1; + flatBitmap->unflatten(&mBitmaps[index], &mRCPlayback); + } + } + + const SkTDArray<const SkFlatMatrix*>& matrices = recorder.getMatrices(); + mMatrixCount = matrices.count(); + if (mMatrixCount > 0) { + mMatrices = new SkMatrix[mMatrixCount]; + for (const SkFlatMatrix** matrixPtr = matrices.begin(); + matrixPtr != matrices.end(); matrixPtr++) { + const SkFlatMatrix* flatMatrix = *matrixPtr; + flatMatrix->unflatten(&mMatrices[flatMatrix->index() - 1]); + } + } + + const SkTDArray<const SkFlatPaint*>& paints = recorder.getPaints(); + mPaintCount = paints.count(); + if (mPaintCount > 0) { + mPaints = new SkPaint[mPaintCount]; + for (const SkFlatPaint** flatPaintPtr = paints.begin(); + flatPaintPtr != paints.end(); flatPaintPtr++) { + const SkFlatPaint* flatPaint = *flatPaintPtr; + int index = flatPaint->index() - 1; + flatPaint->unflatten(&mPaints[index], &mRCPlayback, &mTFPlayback); + } + } + + mPathHeap = recorder.mPathHeap; + mPathHeap->safeRef(); +} + +DisplayList::~DisplayList() { + sk_free((void*) mReader.base()); + + Caches& caches = Caches::getInstance(); + for (int i = 0; i < mBitmapCount; i++) { + caches.textureCache.remove(&mBitmaps[i]); + } + + delete[] mBitmaps; + delete[] mMatrices; + delete[] mPaints; + + mPathHeap->safeUnref(); +} + +void DisplayList::init() { + mBitmaps = NULL; + mMatrices = NULL; + mPaints = NULL; + mPathHeap = NULL; + mBitmapCount = mMatrixCount = mPaintCount = 0; +} + +void DisplayList::replay(OpenGLRenderer& renderer) { + TextContainer text; + mReader.rewind(); + + int saveCount = renderer.getSaveCount() - 1; + + while (!mReader.eof()) { + switch (mReader.readInt()) { + case AcquireContext: { + renderer.acquireContext(); + } + break; + case ReleaseContext: { + renderer.releaseContext(); + } + break; + case Save: { + renderer.save(getInt()); + } + break; + case Restore: { + renderer.restore(); + } + break; + case RestoreToCount: { + renderer.restoreToCount(saveCount + getInt()); + } + break; + case SaveLayer: { + renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(), + getPaint(), getInt()); + } + break; + case Translate: { + renderer.translate(getFloat(), getFloat()); + } + break; + case Rotate: { + renderer.rotate(getFloat()); + } + break; + case Scale: { + renderer.scale(getFloat(), getFloat()); + } + break; + case SetMatrix: { + renderer.setMatrix(getMatrix()); + } + break; + case ConcatMatrix: { + renderer.concatMatrix(getMatrix()); + } + break; + case ClipRect: { + renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(), + (SkRegion::Op) getInt()); + } + break; + case DrawBitmap: { + renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint()); + } + break; + case DrawBitmapMatrix: { + renderer.drawBitmap(getBitmap(), getMatrix(), getPaint()); + } + break; + case DrawBitmapRect: { + renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(), + getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + } + 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); + + renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, + numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + } + break; + case DrawColor: { + renderer.drawColor(getInt(), (SkXfermode::Mode) getInt()); + } + break; + case DrawRect: { + renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + } + break; + case DrawPath: { + renderer.drawPath(getPath(), getPaint()); + } + break; + case DrawLines: { + int count = 0; + float* points = getFloats(count); + renderer.drawLines(points, count, getPaint()); + } + break; + case DrawText: { + getText(&text); + renderer.drawText(text.text(), text.length(), getInt(), + getFloat(), getFloat(), getPaint()); + } + break; + case ResetShader: { + renderer.resetShader(); + } + break; + case SetupShader: { + // TODO: Implement + } + break; + case ResetColorFilter: { + renderer.resetColorFilter(); + } + break; + case SetupColorFilter: { + // TODO: Implement + } + break; + case ResetShadow: { + renderer.resetShadow(); + } + break; + case SetupShadow: { + renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt()); + } + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Base structure +/////////////////////////////////////////////////////////////////////////////// + +DisplayListRenderer::DisplayListRenderer(): + mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) { + mBitmapIndex = mMatrixIndex = mPaintIndex = 1; + mPathHeap = NULL; +} + +DisplayListRenderer::~DisplayListRenderer() { + reset(); +} + +void DisplayListRenderer::reset() { + if (mPathHeap) { + mPathHeap->unref(); + mPathHeap = NULL; + } + + mBitmaps.reset(); + mMatrices.reset(); + mPaints.reset(); + + mWriter.reset(); + mHeap.reset(); + + mRCRecorder.reset(); + mTFRecorder.reset(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Operations +/////////////////////////////////////////////////////////////////////////////// + +void DisplayListRenderer::setViewport(int width, int height) { + mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); + + mWidth = width; + mHeight = height; +} + +void DisplayListRenderer::prepare(bool opaque) { + mSnapshot = new Snapshot(mFirstSnapshot, + SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + mSaveCount = 1; + mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); +} + +void DisplayListRenderer::acquireContext() { + addOp(DisplayList::AcquireContext); + OpenGLRenderer::acquireContext(); +} + +void DisplayListRenderer::releaseContext() { + addOp(DisplayList::ReleaseContext); + OpenGLRenderer::releaseContext(); +} + +int DisplayListRenderer::save(int flags) { + addOp(DisplayList::Save); + addInt(flags); + return OpenGLRenderer::save(flags); +} + +void DisplayListRenderer::restore() { + addOp(DisplayList::Restore); + OpenGLRenderer::restore(); +} + +void DisplayListRenderer::restoreToCount(int saveCount) { + addOp(DisplayList::RestoreToCount); + addInt(saveCount); + OpenGLRenderer::restoreToCount(saveCount); +} + +int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags) { + addOp(DisplayList::SaveLayer); + addBounds(left, top, right, bottom); + addPaint(p); + addInt(flags); + return OpenGLRenderer::save(flags); +} + +void DisplayListRenderer::translate(float dx, float dy) { + addOp(DisplayList::Translate); + addPoint(dx, dy); + OpenGLRenderer::translate(dx, dy); +} + +void DisplayListRenderer::rotate(float degrees) { + addOp(DisplayList::Rotate); + addFloat(degrees); + OpenGLRenderer::rotate(degrees); +} + +void DisplayListRenderer::scale(float sx, float sy) { + addOp(DisplayList::Scale); + addPoint(sx, sy); + OpenGLRenderer::scale(sx, sy); +} + +void DisplayListRenderer::setMatrix(SkMatrix* matrix) { + addOp(DisplayList::SetMatrix); + addMatrix(matrix); + OpenGLRenderer::setMatrix(matrix); +} + +void DisplayListRenderer::concatMatrix(SkMatrix* matrix) { + addOp(DisplayList::ConcatMatrix); + addMatrix(matrix); + OpenGLRenderer::concatMatrix(matrix); +} + +bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom, + SkRegion::Op op) { + addOp(DisplayList::ClipRect); + addBounds(left, top, right, bottom); + addInt(op); + return OpenGLRenderer::clipRect(left, top, right, bottom, op); +} + +void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, + const SkPaint* paint) { + addOp(DisplayList::DrawBitmap); + addBitmap(bitmap); + addPoint(left, top); + addPaint(paint); +} + +void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, + const SkPaint* paint) { + addOp(DisplayList::DrawBitmapMatrix); + addBitmap(bitmap); + addMatrix(matrix); + addPaint(paint); +} + +void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint) { + addOp(DisplayList::DrawBitmapRect); + addBitmap(bitmap); + addBounds(srcLeft, srcTop, srcRight, srcBottom); + addBounds(dstLeft, dstTop, dstRight, dstBottom); + addPaint(paint); +} + +void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint) { + addOp(DisplayList::DrawPatch); + addBitmap(bitmap); + addInts(xDivs, width); + addInts(yDivs, height); + addUInts(colors, numColors); + addBounds(left, top, right, bottom); + addPaint(paint); +} + +void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) { + addOp(DisplayList::DrawColor); + addInt(color); + addInt(mode); +} + +void DisplayListRenderer::drawRect(float left, float top, float right, float bottom, + const SkPaint* paint) { + addOp(DisplayList::DrawRect); + addBounds(left, top, right, bottom); + addPaint(paint); +} + +void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) { + addOp(DisplayList::DrawPath); + addPath(path); + addPaint(paint); +} + +void DisplayListRenderer::drawLines(float* points, int count, const SkPaint* paint) { + addOp(DisplayList::DrawLines); + addFloats(points, count); + addPaint(paint); +} + +void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, + float x, float y, SkPaint* paint) { + addOp(DisplayList::DrawText); + addText(text, bytesCount); + addInt(count); + addPoint(x, y); + addPaint(paint); +} + +void DisplayListRenderer::resetShader() { + addOp(DisplayList::ResetShader); + OpenGLRenderer::resetShader(); +} + +void DisplayListRenderer::setupShader(SkiaShader* shader) { + // TODO: Implement + OpenGLRenderer::setupShader(shader); +} + +void DisplayListRenderer::resetColorFilter() { + addOp(DisplayList::ResetColorFilter); + OpenGLRenderer::resetColorFilter(); +} + +void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) { + // TODO: Implement + OpenGLRenderer::setupColorFilter(filter); +} + +void DisplayListRenderer::resetShadow() { + addOp(DisplayList::ResetShadow); + OpenGLRenderer::resetShadow(); +} + +void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) { + addOp(DisplayList::SetupShadow); + addFloat(radius); + addPoint(dx, dy); + addInt(color); + OpenGLRenderer::setupShadow(radius, dx, dy, color); +} + +/////////////////////////////////////////////////////////////////////////////// +// Recording management +/////////////////////////////////////////////////////////////////////////////// + +int DisplayListRenderer::find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint) { + if (paint == NULL) { + return 0; + } + + SkFlatPaint* flat = SkFlatPaint::Flatten(&mHeap, *paint, mPaintIndex, + &mRCRecorder, &mTFRecorder); + int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(), + paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); + if (index >= 0) { + (void) mHeap.unalloc(flat); + return paints[index]->index(); + } + + index = ~index; + *paints.insert(index) = flat; + return mPaintIndex++; +} + +int DisplayListRenderer::find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix) { + if (matrix == NULL) { + return 0; + } + + SkFlatMatrix* flat = SkFlatMatrix::Flatten(&mHeap, *matrix, mMatrixIndex); + int index = SkTSearch<SkFlatData>((const SkFlatData**) matrices.begin(), + matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); + if (index >= 0) { + (void) mHeap.unalloc(flat); + return matrices[index]->index(); + } + index = ~index; + *matrices.insert(index) = flat; + return mMatrixIndex++; +} + +int DisplayListRenderer::find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap) { + SkFlatBitmap* flat = SkFlatBitmap::Flatten(&mHeap, bitmap, mBitmapIndex, &mRCRecorder); + int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(), + bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); + if (index >= 0) { + (void) mHeap.unalloc(flat); + return bitmaps[index]->index(); + } + index = ~index; + *bitmaps.insert(index) = flat; + return mBitmapIndex++; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h new file mode 100644 index 0000000..9e6d5b1 --- /dev/null +++ b/libs/hwui/DisplayListRenderer.h @@ -0,0 +1,383 @@ +/* + * 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_UI_DISPLAY_LIST_RENDERER_H +#define ANDROID_UI_DISPLAY_LIST_RENDERER_H + +#include <SkChunkAlloc.h> +#include <SkFlattenable.h> +#include <SkMatrix.h> +#include <SkPaint.h> +#include <SkPath.h> +#include <SkPictureFlat.h> +#include <SkRefCnt.h> +#include <SkTDArray.h> +#include <SkTSearch.h> + +#include "OpenGLRenderer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define MIN_WRITER_SIZE 16384 +#define HEAP_BLOCK_SIZE 4096 + +/////////////////////////////////////////////////////////////////////////////// +// Helpers +/////////////////////////////////////////////////////////////////////////////// + +class PathHeap: public SkRefCnt { +public: + PathHeap(); + PathHeap(SkFlattenableReadBuffer& buffer); + ~PathHeap(); + + int append(const SkPath& path); + + int count() const { return mPaths.count(); } + + SkPath& operator[](int index) const { + return *mPaths[index]; + } + + void flatten(SkFlattenableWriteBuffer& buffer) const; + +private: + SkChunkAlloc mHeap; + SkTDArray<SkPath*> mPaths; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Display list +/////////////////////////////////////////////////////////////////////////////// + +class DisplayListRenderer; + +/** + * Replays recorded drawing commands. + */ +class DisplayList { +public: + DisplayList(const DisplayListRenderer& recorder); + ~DisplayList(); + + enum Op { + AcquireContext, + ReleaseContext, + Save, + Restore, + RestoreToCount, + SaveLayer, + Translate, + Rotate, + Scale, + SetMatrix, + ConcatMatrix, + ClipRect, + DrawBitmap, + DrawBitmapMatrix, + DrawBitmapRect, + DrawPatch, + DrawColor, + DrawRect, + DrawPath, + DrawLines, + DrawText, + ResetShader, + SetupShader, + ResetColorFilter, + SetupColorFilter, + ResetShadow, + SetupShadow + }; + + void replay(OpenGLRenderer& renderer); + +private: + void init(); + + class TextContainer { + public: + size_t length() const { + return mByteLength; + } + + const char* text() const { + return (const char*) mText; + } + + size_t mByteLength; + const char* mText; + }; + + SkBitmap* getBitmap() { + int index = getInt(); + return &mBitmaps[index - 1]; + } + + inline int getIndex() { + return mReader.readInt(); + } + + inline int getInt() { + return mReader.readInt(); + } + + SkMatrix* getMatrix() { + int index = getInt(); + if (index == 0) { + return NULL; + } + return &mMatrices[index - 1]; + } + + SkPath* getPath() { + return &(*mPathHeap)[getInt() - 1]; + } + + SkPaint* getPaint() { + int index = getInt(); + if (index == 0) { + return NULL; + } + return &mPaints[index - 1]; + } + + inline float getFloat() { + return mReader.readScalar(); + } + + int32_t* getInts(uint32_t& count) { + count = getInt(); + return (int32_t*) mReader.skip(count * sizeof(int32_t)); + } + + uint32_t* getUInts(int8_t& count) { + count = getInt(); + return (uint32_t*) mReader.skip(count * sizeof(uint32_t)); + } + + float* getFloats(int& count) { + count = getInt(); + return (float*) mReader.skip(count * sizeof(float)); + } + + void getText(TextContainer* text) { + size_t length = text->mByteLength = getInt(); + text->mText = (const char*) mReader.skip(length); + } + + PathHeap* mPathHeap; + + SkBitmap* mBitmaps; + int mBitmapCount; + + SkMatrix* mMatrices; + int mMatrixCount; + + SkPaint* mPaints; + int mPaintCount; + + mutable SkFlattenableReadBuffer mReader; + + SkRefCntPlayback mRCPlayback; + SkTypefacePlayback mTFPlayback; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////// + +/** + * Records drawing commands in a display list for latter playback. + */ +class DisplayListRenderer: public OpenGLRenderer { +public: + DisplayListRenderer(); + ~DisplayListRenderer(); + + void setViewport(int width, int height); + void prepare(bool opaque); + + void acquireContext(); + void releaseContext(); + + int save(int flags); + void restore(); + void restoreToCount(int saveCount); + + int saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags); + + void translate(float dx, float dy); + void rotate(float degrees); + void scale(float sx, float sy); + + void setMatrix(SkMatrix* matrix); + void concatMatrix(SkMatrix* matrix); + + bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); + + void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint); + void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint); + void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint); + void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint); + void drawColor(int color, SkXfermode::Mode mode); + void drawRect(float left, float top, float right, float bottom, const SkPaint* paint); + void drawPath(SkPath* path, SkPaint* paint); + void drawLines(float* points, int count, const SkPaint* paint); + void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint); + + void resetShader(); + void setupShader(SkiaShader* shader); + + void resetColorFilter(); + void setupColorFilter(SkiaColorFilter* filter); + + void resetShadow(); + void setupShadow(float radius, float dx, float dy, int color); + + void reset(); + + DisplayList* getDisplayList() const { + return new DisplayList(*this); + } + + const SkWriter32& writeStream() const { + return mWriter; + } + + const SkTDArray<const SkFlatBitmap*>& getBitmaps() const { + return mBitmaps; + } + + const SkTDArray<const SkFlatMatrix*>& getMatrices() const { + return mMatrices; + } + + const SkTDArray<const SkFlatPaint*>& getPaints() const { + return mPaints; + } + +private: + inline void addOp(DisplayList::Op drawOp) { + mWriter.writeInt(drawOp); + } + + inline void addInt(int value) { + mWriter.writeInt(value); + } + + void addInts(const int32_t* values, uint32_t count) { + mWriter.writeInt(count); + for (uint32_t i = 0; i < count; i++) { + mWriter.writeInt(values[i]); + } + } + + void addUInts(const uint32_t* values, int8_t count) { + mWriter.writeInt(count); + for (int8_t i = 0; i < count; i++) { + mWriter.writeInt(values[i]); + } + } + + inline void addFloat(float value) { + mWriter.writeScalar(value); + } + + void addFloats(const float* values, int count) { + mWriter.writeInt(count); + for (int i = 0; i < count; i++) { + mWriter.writeScalar(values[i]); + } + } + + inline void addPoint(float x, float y) { + mWriter.writeScalar(x); + mWriter.writeScalar(y); + } + + inline void addBounds(float left, float top, float right, float bottom) { + mWriter.writeScalar(left); + mWriter.writeScalar(top); + mWriter.writeScalar(right); + mWriter.writeScalar(bottom); + } + + inline void addText(const void* text, size_t byteLength) { + mWriter.writeInt(byteLength); + mWriter.writePad(text, byteLength); + } + + inline void addPath(const SkPath* path) { + if (mPathHeap == NULL) { + mPathHeap = new PathHeap(); + } + addInt(mPathHeap->append(*path)); + } + + int find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint); + + inline void addPaint(const SkPaint* paint) { + addInt(find(mPaints, paint)); + } + + int find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix); + + inline void addMatrix(const SkMatrix* matrix) { + addInt(find(mMatrices, matrix)); + } + + int find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap); + + inline void addBitmap(const SkBitmap* bitmap) { + addInt(find(mBitmaps, *bitmap)); + } + + SkChunkAlloc mHeap; + + int mBitmapIndex; + SkTDArray<const SkFlatBitmap*> mBitmaps; + + int mMatrixIndex; + SkTDArray<const SkFlatMatrix*> mMatrices; + + int mPaintIndex; + SkTDArray<const SkFlatPaint*> mPaints; + + PathHeap* mPathHeap; + SkWriter32 mWriter; + + SkRefCntRecorder mRCRecorder; + SkRefCntRecorder mTFRecorder; + + friend class DisplayList; + +}; // class DisplayListRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_DISPLAY_LIST_RENDERER_H diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h new file mode 100644 index 0000000..d50d36e --- /dev/null +++ b/libs/hwui/Extensions.h @@ -0,0 +1,96 @@ +/* + * 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_UI_EXTENSIONS_H +#define ANDROID_UI_EXTENSIONS_H + +#include <utils/SortedVector.h> +#include <utils/String8.h> + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#define DEBUG_EXTENSIONS 0 + +// Debug +#if DEBUG_EXTENSIONS + #define EXT_LOGD(...) LOGD(__VA_ARGS__) +#else + #define EXT_LOGD(...) +#endif + +class Extensions { +public: + Extensions() { + const char* buffer = (const char*) glGetString(GL_EXTENSIONS); + const char* current = buffer; + const char* head = current; + EXT_LOGD("Available GL extensions:"); + do { + head = strchr(current, ' '); + String8 s(current, head ? head - current : strlen(current)); + if (s.length()) { + mExtensionList.add(s); + EXT_LOGD(" %s", s.string()); + } + current = head + 1; + } while (head); + + mHasNPot = hasExtension("GL_OES_texture_npot"); + mHasDrawPath = hasExtension("GL_NV_draw_path"); + mHasCoverageSample = hasExtension("GL_NV_coverage_sample"); + mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch"); + + mExtensions = buffer; + } + + inline bool hasNPot() const { return mHasNPot; } + inline bool hasDrawPath() const { return mHasDrawPath; } + inline bool hasCoverageSample() const { return mHasCoverageSample; } + inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; } + + bool hasExtension(const char* extension) const { + const String8 s(extension); + return mExtensionList.indexOf(s) >= 0; + } + + void dump() { + LOGD("Supported extensions:\n%s", mExtensions); + } + +private: + SortedVector<String8> mExtensionList; + + const char* mExtensions; + + bool mHasNPot; + bool mHasDrawPath; + bool mHasCoverageSample; + bool mHasFramebufferFetch; +}; // class Extensions + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_EXTENSIONS_H diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp new file mode 100644 index 0000000..2ef71c2 --- /dev/null +++ b/libs/hwui/FboCache.cpp @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <stdlib.h> + +#include "FboCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_FBO_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting fbo cache size to %s", property); + mMaxSize = atoi(property); + } else { + LOGD(" Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE); + } +} + +FboCache::~FboCache() { + clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t FboCache::getSize() { + return mCache.size(); +} + +uint32_t FboCache::getMaxSize() { + return mMaxSize; +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void FboCache::clear() { + for (size_t i = 0; i < mCache.size(); i++) { + const GLuint fbo = mCache.itemAt(i); + glDeleteFramebuffers(1, &fbo); + } + mCache.clear(); +} + +GLuint FboCache::get() { + GLuint fbo; + if (mCache.size() > 0) { + fbo = mCache.itemAt(mCache.size() - 1); + mCache.removeAt(mCache.size() - 1); + } else { + glGenFramebuffers(1, &fbo); + } + return fbo; +} + +bool FboCache::put(GLuint fbo) { + if (mCache.size() < mMaxSize) { + mCache.add(fbo); + return true; + } + + glDeleteFramebuffers(1, &fbo); + return false; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h new file mode 100644 index 0000000..ec4afe9 --- /dev/null +++ b/libs/hwui/FboCache.h @@ -0,0 +1,79 @@ +/* + * 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_UI_FBO_CACHE_H +#define ANDROID_UI_FBO_CACHE_H + +#include <GLES2/gl2.h> + +#include <utils/SortedVector.h> + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Cache +/////////////////////////////////////////////////////////////////////////////// + +class FboCache { +public: + FboCache(); + ~FboCache(); + + /** + * Returns an FBO from the cache. If no FBO is available, a new one + * is created. If creating a new FBO fails, 0 is returned. + * + * When an FBO is obtained from the cache, it is removed and the + * total number of FBOs available in the cache decreases. + * + * @return The name of the FBO, or 0 if no FBO can be obtained. + */ + GLuint get(); + + /** + * Adds the specified FBO to the cache. + * + * @param fbo The FBO to add to the cache. + * + * @return True if the FBO was added, false otherwise. + */ + bool put(GLuint fbo); + + /** + * Clears the cache. This causes all FBOs to be deleted. + */ + void clear(); + + /** + * Returns the current size of the cache. + */ + uint32_t getSize(); + + /** + * Returns the maximum number of FBOs that the cache can hold. + */ + uint32_t getMaxSize(); + +private: + SortedVector<GLuint> mCache; + uint32_t mMaxSize; +}; // class FboCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_FBO_CACHE_H diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp new file mode 100644 index 0000000..1b21aee --- /dev/null +++ b/libs/hwui/FontRenderer.cpp @@ -0,0 +1,833 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <SkUtils.h> + +#include <cutils/properties.h> + +#include <utils/Log.h> + +#include "FontRenderer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define DEFAULT_TEXT_CACHE_WIDTH 1024 +#define DEFAULT_TEXT_CACHE_HEIGHT 256 + +/////////////////////////////////////////////////////////////////////////////// +// Font +/////////////////////////////////////////////////////////////////////////////// + +Font::Font(FontRenderer* state, uint32_t fontId, float fontSize) : + mState(state), mFontId(fontId), mFontSize(fontSize) { +} + + +Font::~Font() { + for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { + if (mState->mActiveFonts[ct] == this) { + mState->mActiveFonts.removeAt(ct); + break; + } + } + + for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { + CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i); + delete glyph; + } +} + +void Font::invalidateTextureCache() { + for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { + mCachedGlyphs.valueAt(i)->mIsValid = false; + } +} + +void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { + int nPenX = x + glyph->mBitmapLeft; + int nPenY = y + glyph->mBitmapTop; + + int width = (int) glyph->mBitmapWidth; + int height = (int) glyph->mBitmapHeight; + + if (bounds->bottom > nPenY) { + bounds->bottom = nPenY; + } + if (bounds->left > nPenX) { + bounds->left = nPenX; + } + if (bounds->right < nPenX + width) { + bounds->right = nPenX + width; + } + if (bounds->top < nPenY + height) { + bounds->top = nPenY + height; + } +} + +void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { + int nPenX = x + glyph->mBitmapLeft; + int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; + + float u1 = glyph->mBitmapMinU; + float u2 = glyph->mBitmapMaxU; + float v1 = glyph->mBitmapMinV; + float v2 = glyph->mBitmapMaxV; + + int width = (int) glyph->mBitmapWidth; + int height = (int) glyph->mBitmapHeight; + + mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2, + nPenX + width, nPenY, 0, u2, v2, + nPenX + width, nPenY - height, 0, u2, v1, + nPenX, nPenY - height, 0, u1, v1); +} + +void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { + int nPenX = x + glyph->mBitmapLeft; + int nPenY = y + glyph->mBitmapTop; + + uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; + uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; + + uint32_t cacheWidth = mState->getCacheWidth(); + const uint8_t* cacheBuffer = mState->getTextTextureData(); + + uint32_t cacheX = 0, cacheY = 0; + int32_t bX = 0, bY = 0; + for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { + for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { + if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { + LOGE("Skipping invalid index"); + continue; + } + uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; + bitmap[bY * bitmapW + bX] = tempCol; + } + } + +} + +Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) { + CachedGlyphInfo* cachedGlyph = NULL; + ssize_t index = mCachedGlyphs.indexOfKey(utfChar); + if (index >= 0) { + cachedGlyph = mCachedGlyphs.valueAt(index); + } else { + cachedGlyph = cacheGlyph(paint, utfChar); + } + + // Is the glyph still in texture cache? + if (!cachedGlyph->mIsValid) { + const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); + updateGlyphCache(paint, skiaGlyph, cachedGlyph); + } + + return cachedGlyph; +} + +void Font::renderUTF(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, + bitmapW, bitmapH, NULL); + } else { + renderUTF(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, + 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); +} + +#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) + +void Font::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) { + if (numGlyphs == 0 || text == NULL || len == 0) { + return; + } + + SkFixed penX = SkIntToFixed(x); + int penY = y; + int glyphsLeft = 1; + if (numGlyphs > 0) { + glyphsLeft = numGlyphs; + } + + SkFixed prevRsbDelta = 0; + penX += SK_Fixed1 / 2; + + text += start; + + while (glyphsLeft > 0) { + int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); + + // Reached the end of the string + if (utfChar < 0) { + break; + } + + CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); + penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta); + prevRsbDelta = cachedGlyph->mRsbDelta; + + // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage + if (cachedGlyph->mIsValid) { + switch(mode) { + case FRAMEBUFFER: + drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY); + break; + case BITMAP: + drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bitmap, bitmapW, bitmapH); + break; + case MEASURE: + measureCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bounds); + break; + } + } + + penX += cachedGlyph->mAdvanceX; + + // If we were given a specific number of glyphs, decrement + if (numGlyphs > 0) { + glyphsLeft--; + } + } +} + +void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { + glyph->mAdvanceX = skiaGlyph.fAdvanceX; + glyph->mAdvanceY = skiaGlyph.fAdvanceY; + glyph->mBitmapLeft = skiaGlyph.fLeft; + glyph->mBitmapTop = skiaGlyph.fTop; + glyph->mLsbDelta = skiaGlyph.fLsbDelta; + glyph->mRsbDelta = skiaGlyph.fRsbDelta; + + uint32_t startX = 0; + uint32_t startY = 0; + + // Get the bitmap for the glyph + paint->findImage(skiaGlyph); + glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); + + if (!glyph->mIsValid) { + return; + } + + uint32_t endX = startX + skiaGlyph.fWidth; + uint32_t endY = startY + skiaGlyph.fHeight; + + glyph->mStartX = startX; + glyph->mStartY = startY; + glyph->mBitmapWidth = skiaGlyph.fWidth; + glyph->mBitmapHeight = skiaGlyph.fHeight; + + uint32_t cacheWidth = mState->getCacheWidth(); + uint32_t cacheHeight = mState->getCacheHeight(); + + glyph->mBitmapMinU = (float) startX / (float) cacheWidth; + glyph->mBitmapMinV = (float) startY / (float) cacheHeight; + glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; + glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; + + mState->mUploadTexture = true; +} + +Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { + CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); + mCachedGlyphs.add(glyph, newGlyph); + + const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); + newGlyph->mGlyphIndex = skiaGlyph.fID; + newGlyph->mIsValid = false; + + updateGlyphCache(paint, skiaGlyph, newGlyph); + + return newGlyph; +} + +Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) { + Vector<Font*> &activeFonts = state->mActiveFonts; + + for (uint32_t i = 0; i < activeFonts.size(); i++) { + Font* font = activeFonts[i]; + if (font->mFontId == fontId && font->mFontSize == fontSize) { + return font; + } + } + + Font* newFont = new Font(state, fontId, fontSize); + activeFonts.push(newFont); + return newFont; +} + +/////////////////////////////////////////////////////////////////////////////// +// FontRenderer +/////////////////////////////////////////////////////////////////////////////// + +FontRenderer::FontRenderer() { + LOGD("Creating FontRenderer"); + + mGammaTable = NULL; + mInitialized = false; + mMaxNumberOfQuads = 1024; + mCurrentQuadIndex = 0; + mTextureId = 0; + + mTextMeshPtr = NULL; + mTextTexture = NULL; + + mIndexBufferID = 0; + + mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; + mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; + + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { + LOGD(" Setting text cache width to %s pixels", property); + mCacheWidth = atoi(property); + } else { + LOGD(" Using default text cache width of %i pixels", mCacheWidth); + } + + if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { + LOGD(" Setting text cache width to %s pixels", property); + mCacheHeight = atoi(property); + } else { + LOGD(" Using default text cache height of %i pixels", mCacheHeight); + } +} + +FontRenderer::~FontRenderer() { + for (uint32_t i = 0; i < mCacheLines.size(); i++) { + delete mCacheLines[i]; + } + mCacheLines.clear(); + + if (mInitialized) { + delete[] mTextMeshPtr; + delete[] mTextTexture; + } + + if (mTextureId) { + glDeleteTextures(1, &mTextureId); + } + + Vector<Font*> fontsToDereference = mActiveFonts; + for (uint32_t i = 0; i < fontsToDereference.size(); i++) { + delete fontsToDereference[i]; + } +} + +void FontRenderer::flushAllAndInvalidate() { + if (mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } + for (uint32_t i = 0; i < mActiveFonts.size(); i++) { + mActiveFonts[i]->invalidateTextureCache(); + } + for (uint32_t i = 0; i < mCacheLines.size(); i++) { + mCacheLines[i]->mCurrentCol = 0; + } +} + +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; + } + + // Now copy the bitmap into the cache texture + uint32_t startX = 0; + uint32_t startY = 0; + + bool bitmapFit = false; + for (uint32_t i = 0; i < mCacheLines.size(); i++) { + bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); + if (bitmapFit) { + break; + } + } + + // If the new glyph didn't fit, flush the state so far and invalidate everything + if (!bitmapFit) { + flushAllAndInvalidate(); + + // Try to fit it again + for (uint32_t i = 0; i < mCacheLines.size(); i++) { + bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); + if (bitmapFit) { + break; + } + } + + // if we still don't fit, something is wrong and we shouldn't draw + if (!bitmapFit) { + LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", + (int) glyph.fWidth, (int) glyph.fHeight); + return false; + } + } + + *retOriginX = startX; + *retOriginY = startY; + + uint32_t endX = startX + glyph.fWidth; + uint32_t endY = startY + glyph.fHeight; + + uint32_t cacheWidth = mCacheWidth; + + uint8_t* cacheBuffer = mTextTexture; + uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; + unsigned int stride = glyph.rowBytes(); + + uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; + for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { + for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { + uint8_t tempCol = bitmapBuffer[bY * stride + bX]; + cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; + } + } + + return true; +} + +void FontRenderer::initTextTexture() { + mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; + memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); + + mUploadTexture = false; + + glGenTextures(1, &mTextureId); + glBindTexture(GL_TEXTURE_2D, mTextureId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // Initialize texture dimentions + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, 0); + + mLinearFiltering = false; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Split up our cache texture into lines of certain widths + int nextLine = 0; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); +} + +// Avoid having to reallocate memory and render quad by quad +void FontRenderer::initVertexArrayBuffers() { + uint32_t numIndicies = mMaxNumberOfQuads * 6; + uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t); + uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); + + // Four verts, two triangles , six indices per quad + for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { + int i6 = i * 6; + int i4 = i * 4; + + indexBufferData[i6 + 0] = i4 + 0; + indexBufferData[i6 + 1] = i4 + 1; + indexBufferData[i6 + 2] = i4 + 2; + + indexBufferData[i6 + 3] = i4 + 0; + indexBufferData[i6 + 4] = i4 + 2; + indexBufferData[i6 + 5] = i4 + 3; + } + + glGenBuffers(1, &mIndexBufferID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + free(indexBufferData); + + uint32_t coordSize = 3; + uint32_t uvSize = 2; + uint32_t vertsPerQuad = 4; + uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; + mTextMeshPtr = new float[vertexBufferSize]; +} + +// We don't want to allocate anything unless we actually draw text +void FontRenderer::checkInit() { + if (mInitialized) { + return; + } + + initTextTexture(); + initVertexArrayBuffers(); + + // We store a string with letters in a rough frequency of occurrence + mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); + mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); + mLatinPrecache += String16(",.?!()-+@;:`'"); + mLatinPrecache += String16("0123456789"); + + mInitialized = true; +} + +void FontRenderer::checkTextureUpdate() { + if (!mUploadTexture) { + return; + } + + glBindTexture(GL_TEXTURE_2D, mTextureId); + + // Iterate over all the cache lines and see which ones need to be updated + for (uint32_t i = 0; i < mCacheLines.size(); i++) { + CacheTextureLine* cl = mCacheLines[i]; + if(cl->mDirty) { + uint32_t xOffset = 0; + uint32_t yOffset = cl->mCurrentRow; + uint32_t width = mCacheWidth; + uint32_t height = cl->mMaxHeight; + void* textureData = mTextTexture + yOffset*width; + + glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, + GL_ALPHA, GL_UNSIGNED_BYTE, textureData); + + cl->mDirty = false; + } + } + + mUploadTexture = false; +} + +void FontRenderer::issueDrawCommand() { + checkTextureUpdate(); + + float* vtx = mTextMeshPtr; + float* tex = vtx + 3; + + // position is slot 0 + uint32_t slot = 0; + glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx); + + // texture0 is slot 1 + slot = 1; + glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); + glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); +} + +void FontRenderer::appendMeshQuad(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 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { + return; + } + + const uint32_t vertsPerQuad = 4; + const uint32_t floatsPerVert = 5; + float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; + + (*currentPos++) = x1; + (*currentPos++) = y1; + (*currentPos++) = z1; + (*currentPos++) = u1; + (*currentPos++) = v1; + + (*currentPos++) = x2; + (*currentPos++) = y2; + (*currentPos++) = z2; + (*currentPos++) = u2; + (*currentPos++) = v2; + + (*currentPos++) = x3; + (*currentPos++) = y3; + (*currentPos++) = z3; + (*currentPos++) = u3; + (*currentPos++) = v3; + + (*currentPos++) = x4; + (*currentPos++) = y4; + (*currentPos++) = z4; + (*currentPos++) = u4; + (*currentPos++) = v4; + + mCurrentQuadIndex++; + + if (mCurrentQuadIndex == mMaxNumberOfQuads) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +uint32_t FontRenderer::getRemainingCacheCapacity() { + uint32_t remainingCapacity = 0; + float totalPixels = 0; + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); + totalPixels += mCacheLines[i]->mMaxWidth; + } + remainingCapacity = (remainingCapacity * 100) / totalPixels; + return remainingCapacity; +} + +void FontRenderer::precacheLatin(SkPaint* paint) { + // Remaining capacity is measured in % + uint32_t remainingCapacity = getRemainingCacheCapacity(); + uint32_t precacheIdx = 0; + while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { + mCurrentFont->getCachedUTFChar(paint, (int32_t)mLatinPrecache[precacheIdx]); + remainingCapacity = getRemainingCacheCapacity(); + precacheIdx ++; + } +} + +void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { + uint32_t currentNumFonts = mActiveFonts.size(); + mCurrentFont = Font::create(this, fontId, fontSize); + + const float maxPrecacheFontSize = 40.0f; + bool isNewFont = currentNumFonts != mActiveFonts.size(); + + if (isNewFont && fontSize <= maxPrecacheFontSize) { + precacheLatin(paint); + } +} + +FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, + uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { + checkInit(); + + if (!mCurrentFont) { + DropShadow image; + image.width = 0; + image.height = 0; + image.image = NULL; + image.penX = 0; + image.penY = 0; + return image; + } + + Rect bounds; + mCurrentFont->measureUTF(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]; + for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { + dataBuffer[i] = 0; + } + + int penX = radius - bounds.left; + int penY = radius - bounds.bottom; + + mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, + dataBuffer, paddedWidth, paddedHeight); + blurImage(dataBuffer, paddedWidth, paddedHeight, radius); + + DropShadow image; + image.width = paddedWidth; + image.height = paddedHeight; + image.image = dataBuffer; + image.penX = penX; + image.penY = penY; + return image; +} + +void FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, + uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) { + checkInit(); + + if (!mCurrentFont) { + LOGE("No font set"); + return; + } + + mClip = clip; + mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); + + if (mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { + // Compute gaussian weights for the blur + // e is the euler's number + float e = 2.718281828459045f; + float pi = 3.1415926535897932f; + // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) + // x is of the form [-radius .. 0 .. radius] + // and sigma varies with radius. + // Based on some experimental radius values and sigma's + // we approximately fit sigma = f(radius) as + // sigma = radius * 0.3 + 0.6 + // The larger the radius gets, the more our gaussian blur + // will resemble a box blur since with large sigma + // the gaussian curve begins to lose its shape + float sigma = 0.3f * (float)radius + 0.6f; + + // Now compute the coefficints + // We will store some redundant values to save some math during + // the blur calculations + // precompute some values + float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); + float coeff2 = - 1.0f / (2.0f * sigma * sigma); + + float normalizeFactor = 0.0f; + for(int32_t r = -radius; r <= radius; r ++) { + float floatR = (float) r; + weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); + normalizeFactor += weights[r + radius]; + } + + //Now we need to normalize the weights because all our coefficients need to add up to one + normalizeFactor = 1.0f / normalizeFactor; + for(int32_t r = -radius; r <= radius; r ++) { + weights[r + radius] *= normalizeFactor; + } +} + +void FontRenderer::horizontalBlur(float* weights, int32_t radius, + const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { + float blurredPixel = 0.0f; + float currentPixel = 0.0f; + + for(int32_t y = 0; y < height; y ++) { + + const uint8_t* input = source + y * width; + uint8_t* output = dest + y * width; + + for(int32_t x = 0; x < width; x ++) { + blurredPixel = 0.0f; + const float* gPtr = weights; + // Optimization for non-border pixels + if ((x > radius) && (x < (width - radius))) { + const uint8_t *i = input + (x - radius); + for(int r = -radius; r <= radius; r ++) { + currentPixel = (float) (*i); + blurredPixel += currentPixel * gPtr[0]; + gPtr++; + i++; + } + } else { + for(int32_t r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validW = x + r; + if(validW < 0) { + validW = 0; + } + if(validW > width - 1) { + validW = width - 1; + } + + currentPixel = (float)(input[validW]); + blurredPixel += currentPixel * gPtr[0]; + gPtr++; + } + } + *output = (uint8_t)blurredPixel; + output ++; + } + } +} + +void FontRenderer::verticalBlur(float* weights, int32_t radius, + const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { + float blurredPixel = 0.0f; + float currentPixel = 0.0f; + + for(int32_t y = 0; y < height; y ++) { + + uint8_t* output = dest + y * width; + + for(int32_t x = 0; x < width; x ++) { + blurredPixel = 0.0f; + const float* gPtr = weights; + const uint8_t* input = source + x; + // Optimization for non-border pixels + if ((y > radius) && (y < (height - radius))) { + const uint8_t *i = input + ((y - radius) * width); + for(int32_t r = -radius; r <= radius; r ++) { + currentPixel = (float)(*i); + blurredPixel += currentPixel * gPtr[0]; + gPtr++; + i += width; + } + } else { + for(int32_t r = -radius; r <= radius; r ++) { + int validH = y + r; + // Clamp to zero and width + if(validH < 0) { + validH = 0; + } + if(validH > height - 1) { + validH = height - 1; + } + + const uint8_t *i = input + validH * width; + currentPixel = (float)(*i); + blurredPixel += currentPixel * gPtr[0]; + gPtr++; + } + } + *output = (uint8_t)blurredPixel; + output ++; + } + } +} + + +void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { + float *gaussian = new float[2 * radius + 1]; + computeGaussianWeights(gaussian, radius); + uint8_t* scratch = new uint8_t[width * height]; + horizontalBlur(gaussian, radius, image, scratch, width, height); + verticalBlur(gaussian, radius, scratch, image, width, height); + delete[] gaussian; + delete[] scratch; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h new file mode 100644 index 0000000..f10efad --- /dev/null +++ b/libs/hwui/FontRenderer.h @@ -0,0 +1,276 @@ +/* + * 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_UI_FONT_RENDERER_H +#define ANDROID_UI_FONT_RENDERER_H + +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/Vector.h> +#include <utils/KeyedVector.h> + +#include <SkScalerContext.h> +#include <SkPaint.h> + +#include <GLES2/gl2.h> + +#include "Rect.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +class FontRenderer; + +/** + * 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. + */ +class Font { +public: + ~Font(); + + /** + * 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); + /** + * Creates a new font associated with the specified font state. + */ + static Font* create(FontRenderer* state, uint32_t fontId, float fontSize); + +protected: + friend class FontRenderer; + + enum RenderMode { + FRAMEBUFFER, + BITMAP, + 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 measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, + int numGlyphs, Rect *bounds); + + struct CachedGlyphInfo { + // Has the cache been invalidated? + bool mIsValid; + // Location of the cached glyph in the bitmap + // in case we need to resize the texture or + // render to bitmap + uint32_t mStartX; + uint32_t mStartY; + uint32_t mBitmapWidth; + uint32_t mBitmapHeight; + // Also cache texture coords for the quad + float mBitmapMinU; + float mBitmapMinV; + float mBitmapMaxU; + float mBitmapMaxV; + // Minimize how much we call freetype + uint32_t mGlyphIndex; + uint32_t mAdvanceX; + uint32_t mAdvanceY; + // Values below contain a glyph's origin in the bitmap + int32_t mBitmapLeft; + int32_t mBitmapTop; + // Auto-kerning + SkFixed mLsbDelta; + SkFixed mRsbDelta; + }; + + Font(FontRenderer* state, uint32_t fontId, float fontSize); + + DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs; + + void invalidateTextureCache(); + + CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_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); + + CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar); + + FontRenderer* mState; + uint32_t mFontId; + float mFontSize; +}; + +class FontRenderer { +public: + FontRenderer(); + ~FontRenderer(); + + void init(); + void deinit(); + + void setGammaTable(const uint8_t* gammaTable) { + mGammaTable = gammaTable; + } + + void setFont(SkPaint* paint, uint32_t fontId, float fontSize); + void renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, + uint32_t len, int numGlyphs, int x, int y); + + struct DropShadow { + DropShadow() { }; + + DropShadow(const DropShadow& dropShadow): + width(dropShadow.width), height(dropShadow.height), + image(dropShadow.image), penX(dropShadow.penX), + penY(dropShadow.penY) { + } + + uint32_t width; + uint32_t height; + uint8_t* image; + int32_t penX; + int32_t penY; + }; + + // After renderDropShadow returns, the called owns the memory in DropShadow.image + // and is responsible for releasing it when it's done with it + DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex, + uint32_t len, int numGlyphs, uint32_t radius); + + GLuint getTexture(bool linearFiltering = false) { + checkInit(); + if (linearFiltering != mLinearFiltering) { + mLinearFiltering = linearFiltering; + const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; + + glBindTexture(GL_TEXTURE_2D, mTextureId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); + } + return mTextureId; + } + +protected: + friend class Font; + + const uint8_t* mGammaTable; + + struct CacheTextureLine { + uint16_t mMaxHeight; + uint16_t mMaxWidth; + uint32_t mCurrentRow; + uint32_t mCurrentCol; + bool mDirty; + + CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow, + uint32_t currentCol): + mMaxHeight(maxHeight), + mMaxWidth(maxWidth), + mCurrentRow(currentRow), + mCurrentCol(currentCol), + mDirty(false) { + } + + bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { + if (glyph.fHeight + 2 > mMaxHeight) { + return false; + } + + if (mCurrentCol + glyph.fWidth + 2 < mMaxWidth) { + *retOriginX = mCurrentCol + 1; + *retOriginY = mCurrentRow + 1; + mCurrentCol += glyph.fWidth + 2; + mDirty = true; + return true; + } + + return false; + } + }; + + uint32_t getCacheWidth() const { + return mCacheWidth; + } + + uint32_t getCacheHeight() const { + return mCacheHeight; + } + + void initTextTexture(); + bool cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY); + + void flushAllAndInvalidate(); + void initVertexArrayBuffers(); + + void checkInit(); + + String16 mLatinPrecache; + void precacheLatin(SkPaint* paint); + + void issueDrawCommand(); + void appendMeshQuad(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); + + uint32_t mCacheWidth; + uint32_t mCacheHeight; + + Vector<CacheTextureLine*> mCacheLines; + uint32_t getRemainingCacheCapacity(); + + Font* mCurrentFont; + Vector<Font*> mActiveFonts; + + // Texture to cache glyph bitmaps + uint8_t* mTextTexture; + const uint8_t* getTextTextureData() const { + return mTextTexture; + } + GLuint mTextureId; + void checkTextureUpdate(); + bool mUploadTexture; + + // Pointer to vertex data to speed up frame to frame work + float *mTextMeshPtr; + uint32_t mCurrentQuadIndex; + uint32_t mMaxNumberOfQuads; + + uint32_t mIndexBufferID; + + const Rect* mClip; + + bool mInitialized; + + bool mLinearFiltering; + + void computeGaussianWeights(float* weights, int32_t radius); + void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest, + int32_t width, int32_t height); + void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest, + int32_t width, int32_t height); + void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius); +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_FONT_RENDERER_H diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp new file mode 100644 index 0000000..6d087e3 --- /dev/null +++ b/libs/hwui/GammaFontRenderer.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include "GammaFontRenderer.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +GammaFontRenderer::GammaFontRenderer() { + LOGD("Creating gamma font renderer"); + + // Get the renderer properties + char property[PROPERTY_VALUE_MAX]; + + // Get the gamma + float gamma = DEFAULT_TEXT_GAMMA; + if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { + LOGD(" Setting text gamma to %s", property); + gamma = atof(property); + } else { + LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); + } + + // Get the black gamma threshold + mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; + if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { + LOGD(" Setting text black gamma threshold to %s", property); + mBlackThreshold = atoi(property); + } else { + LOGD(" Using default text black gamma threshold of %d", + DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); + } + + // Get the white gamma threshold + mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; + if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { + LOGD(" Setting text white gamma threshold to %s", property); + mWhiteThreshold = atoi(property); + } else { + LOGD(" Using default white black gamma threshold of %d", + DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); + } + + // Compute the gamma tables + const float blackGamma = gamma; + const float whiteGamma = 1.0f / gamma; + + for (uint32_t i = 0; i <= 255; i++) { + mDefault[i] = i; + + const float v = i / 255.0f; + const float black = pow(v, blackGamma); + const float white = pow(v, whiteGamma); + + mBlackGamma[i] = uint8_t((float)::floor(black * 255.0f + 0.5f)); + mWhiteGamma[i] = uint8_t((float)::floor(white * 255.0f + 0.5f)); + } + + // Configure the font renderers + mDefaultRenderer.setGammaTable(&mDefault[0]); + mBlackGammaRenderer.setGammaTable(&mBlackGamma[0]); + mWhiteGammaRenderer.setGammaTable(&mWhiteGamma[0]); +} + +FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) { + if (paint->getShader() == NULL) { + uint32_t c = paint->getColor(); + const int r = (c >> 16) & 0xFF; + const int g = (c >> 8) & 0xFF; + const int b = (c ) & 0xFF; + const int luminance = (r * 2 + g * 5 + b) >> 3; + + if (luminance <= mBlackThreshold) { + return mBlackGammaRenderer; + } else if (luminance >= mWhiteThreshold) { + return mWhiteGammaRenderer; + } + } + return mDefaultRenderer; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h new file mode 100644 index 0000000..5fa45cf --- /dev/null +++ b/libs/hwui/GammaFontRenderer.h @@ -0,0 +1,48 @@ +/* + * 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_UI_GAMMA_FONT_RENDERER_H +#define ANDROID_UI_GAMMA_FONT_RENDERER_H + +#include <SkPaint.h> + +#include "FontRenderer.h" + +namespace android { +namespace uirenderer { + +struct GammaFontRenderer { + GammaFontRenderer(); + + FontRenderer& getFontRenderer(const SkPaint* paint); + +private: + FontRenderer mDefaultRenderer; + FontRenderer mBlackGammaRenderer; + FontRenderer mWhiteGammaRenderer; + + int mBlackThreshold; + int mWhiteThreshold; + + uint8_t mDefault[256]; + uint8_t mBlackGamma[256]; + uint8_t mWhiteGamma[256]; +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_GAMMA_FONT_RENDERER_H diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp new file mode 100644 index 0000000..97f4cb4 --- /dev/null +++ b/libs/hwui/GradientCache.cpp @@ -0,0 +1,188 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <GLES2/gl2.h> + +#include <SkCanvas.h> +#include <SkGradientShader.h> + +#include <utils/threads.h> + +#include "GradientCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +GradientCache::GradientCache(): + mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting gradient cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); + } + + mCache.setOnEntryRemovedListener(this); +} + +GradientCache::GradientCache(uint32_t maxByteSize): + mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(maxByteSize) { + mCache.setOnEntryRemovedListener(this); +} + +GradientCache::~GradientCache() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t GradientCache::getSize() { + Mutex::Autolock _l(mLock); + return mSize; +} + +uint32_t GradientCache::getMaxSize() { + Mutex::Autolock _l(mLock); + return mMaxSize; +} + +void GradientCache::setMaxSize(uint32_t maxSize) { + Mutex::Autolock _l(mLock); + mMaxSize = maxSize; + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +/////////////////////////////////////////////////////////////////////////////// + +void GradientCache::operator()(SkShader*& shader, Texture*& texture) { + // Already locked here + if (shader) { + const uint32_t size = texture->width * texture->height * 4; + mSize -= size; + } + + if (texture) { + glDeleteTextures(1, &texture->id); + delete texture; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +Texture* GradientCache::get(SkShader* shader) { + Mutex::Autolock _l(mLock); + return mCache.get(shader); +} + +void GradientCache::remove(SkShader* shader) { + Mutex::Autolock _l(mLock); + mCache.remove(shader); +} + +void GradientCache::clear() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +Texture* GradientCache::addLinearGradient(SkShader* shader, uint32_t* colors, + float* positions, int count, SkShader::TileMode tileMode) { + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1); + bitmap.allocPixels(); + bitmap.eraseColor(0); + + SkCanvas canvas(bitmap); + + SkPoint points[2]; + points[0].set(0.0f, 0.0f); + points[1].set(bitmap.width(), 0.0f); + + SkShader* localShader = SkGradientShader::CreateLinear(points, + reinterpret_cast<const SkColor*>(colors), positions, count, tileMode); + + SkPaint p; + p.setStyle(SkPaint::kStrokeAndFill_Style); + p.setShader(localShader)->unref(); + + canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p); + + mLock.lock(); + // Asume the cache is always big enough + const uint32_t size = bitmap.rowBytes() * bitmap.height(); + while (mSize + size > mMaxSize) { + mCache.removeOldest(); + } + mLock.unlock(); + + Texture* texture = new Texture; + generateTexture(&bitmap, texture); + + mLock.lock(); + mSize += size; + mCache.put(shader, texture); + mLock.unlock(); + + return texture; +} + +void GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) { + SkAutoLockPixels autoLock(*bitmap); + if (!bitmap->readyToDraw()) { + LOGE("Cannot generate texture from shader"); + return; + } + + texture->generation = bitmap->getGenerationID(); + texture->width = bitmap->width(); + texture->height = bitmap->height(); + + glGenTextures(1, &texture->id); + + glBindTexture(GL_TEXTURE_2D, texture->id); + glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); + + texture->blend = !bitmap->isOpaque(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h new file mode 100644 index 0000000..48877f6 --- /dev/null +++ b/libs/hwui/GradientCache.h @@ -0,0 +1,96 @@ +/* + * 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_UI_GRADIENT_CACHE_H +#define ANDROID_UI_GRADIENT_CACHE_H + +#include <SkShader.h> + +#include "Texture.h" +#include "utils/GenerationCache.h" + +namespace android { +namespace uirenderer { + +/** + * A simple LRU gradient cache. The cache has a maximum size expressed in bytes. + * Any texture added to the cache causing the cache to grow beyond the maximum + * allowed size will also cause the oldest texture to be kicked out. + */ +class GradientCache: public OnEntryRemoved<SkShader*, Texture*> { +public: + GradientCache(); + GradientCache(uint32_t maxByteSize); + ~GradientCache(); + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(SkShader*& shader, Texture*& texture); + + /** + * Adds a new linear gradient to the cache. The generated texture is + * returned. + */ + Texture* addLinearGradient(SkShader* shader, uint32_t* colors, float* positions, + int count, SkShader::TileMode tileMode = SkShader::kClamp_TileMode); + /** + * Returns the texture associated with the specified shader. + */ + Texture* get(SkShader* shader); + /** + * Removes the texture associated with the specified shader. Returns NULL + * if the texture cannot be found. Upon remove the texture is freed. + */ + void remove(SkShader* shader); + /** + * Clears the cache. This causes all textures to be deleted. + */ + void clear(); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + void generateTexture(SkBitmap* bitmap, Texture* texture); + + GenerationCache<SkShader*, Texture*> mCache; + + uint32_t mSize; + uint32_t mMaxSize; + + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ + mutable Mutex mLock; +}; // class GradientCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_GRADIENT_CACHE_H diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h new file mode 100644 index 0000000..2afe2fa --- /dev/null +++ b/libs/hwui/Layer.h @@ -0,0 +1,93 @@ +/* + * 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_UI_LAYER_H +#define ANDROID_UI_LAYER_H + +#include <sys/types.h> + +#include <GLES2/gl2.h> + +#include <SkXfermode.h> + +#include "Rect.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Layers +/////////////////////////////////////////////////////////////////////////////// + +/** + * A layer has dimensions and is backed by an OpenGL texture or FBO. + */ +struct Layer { + Layer(const uint32_t layerWidth, const uint32_t layerHeight): + width(layerWidth), height(layerHeight) { + } + + /** + * Bounds of the layer. + */ + Rect layer; + /** + * Texture coordinates of the layer. + */ + Rect texCoords; + + /** + * Name of the FBO used to render the layer. If the name is 0 + * this layer is not backed by an FBO, but a simple texture. + */ + GLuint fbo; + + /** + * Opacity of the layer. + */ + int alpha; + /** + * Blending mode of the layer. + */ + SkXfermode::Mode mode; + /** + * Indicates whether this layer should be blended. + */ + bool blend; + + /** + * Indicates whether this layer has been used already. + */ + bool empty; + + /** + * Name of the texture used to render the layer. + */ + GLuint texture; + /** + * Width of the layer texture. + */ + uint32_t width; + /** + * Height of the layer texture. + */ + uint32_t height; +}; // struct Layer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_LAYER_H diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp new file mode 100644 index 0000000..9ce0359 --- /dev/null +++ b/libs/hwui/LayerCache.cpp @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <GLES2/gl2.h> + +#include <utils/Log.h> + +#include "LayerCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting layer cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE); + } +} + +LayerCache::~LayerCache() { + clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t LayerCache::getSize() { + return mSize; +} + +uint32_t LayerCache::getMaxSize() { + return mMaxSize; +} + +void LayerCache::setMaxSize(uint32_t maxSize) { + clear(); + mMaxSize = maxSize; +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void LayerCache::deleteLayer(Layer* layer) { + if (layer) { + mSize -= layer->width * layer->height * 4; + glDeleteTextures(1, &layer->texture); + delete layer; + } +} + +void LayerCache::clear() { + size_t count = mCache.size(); + for (size_t i = 0; i < count; i++) { + deleteLayer(mCache.itemAt(i).mLayer); + } + mCache.clear(); +} + +Layer* LayerCache::get(const uint32_t width, const uint32_t height) { + Layer* layer = NULL; + + LayerEntry entry(width, height); + ssize_t index = mCache.indexOf(entry); + + if (index >= 0) { + entry = mCache.itemAt(index); + mCache.removeAt(index); + + layer = entry.mLayer; + mSize -= layer->width * layer->height * 4; + + LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height); + } else { + LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); + + layer = new Layer(entry.mWidth, entry.mHeight); + layer->blend = true; + layer->empty = true; + layer->fbo = 0; + + glGenTextures(1, &layer->texture); + glBindTexture(GL_TEXTURE_2D, layer->texture); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + +#if DEBUG_LAYERS + size_t size = mCache.size(); + for (size_t i = 0; i < size; i++) { + const LayerEntry& entry = mCache.itemAt(i); + LAYER_LOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight); + } +#endif + } + + return layer; +} + +bool LayerCache::put(Layer* layer) { + 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) { + // TODO: Use an LRU + while (mSize + size > mMaxSize) { + size_t position = 0; +#if LAYER_REMOVE_BIGGEST + position = mCache.size() - 1; +#endif + Layer* victim = mCache.itemAt(position).mLayer; + deleteLayer(victim); + mCache.removeAt(position); + + LAYER_LOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(), + victim->layer.getHeight()); + } + + LayerEntry entry(layer); + + mCache.add(entry); + mSize += size; + + return true; + } + return false; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h new file mode 100644 index 0000000..ae792ab --- /dev/null +++ b/libs/hwui/LayerCache.h @@ -0,0 +1,141 @@ +/* + * 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_UI_LAYER_CACHE_H +#define ANDROID_UI_LAYER_CACHE_H + +#include "Layer.h" +#include "utils/SortedList.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#define DEBUG_LAYERS 0 + +// Indicates whether to remove the biggest layers first, or the smaller ones +#define LAYER_REMOVE_BIGGEST 0 +// Textures used by layers must have dimensions multiples of this number +#define LAYER_SIZE 64 + +// Debug +#if DEBUG_LAYERS + #define LAYER_LOGD(...) LOGD(__VA_ARGS__) +#else + #define LAYER_LOGD(...) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Cache +/////////////////////////////////////////////////////////////////////////////// + +class LayerCache { +public: + LayerCache(); + ~LayerCache(); + + /** + * Returns a layer large enough for the specified dimensions. If no suitable + * layer can be found, a new one is created and returned. If creating a new + * layer fails, NULL is returned. + * + * When a layer is obtained from the cache, it is removed and the total + * size of the cache goes down. + * + * @param width The desired width of the layer + * @param width The desired height of the layer + */ + Layer* get(const uint32_t width, const uint32_t height); + + /** + * Adds the layer to the cache. The layer will not be added if there is + * not enough space available. Adding a layer can cause other layers to + * be removed from the cache. + * + * @param layer The layer to add to the cache + * + * @return True if the layer was added, false otherwise. + */ + bool put(Layer* layer); + /** + * Clears the cache. This causes all layers to be deleted. + */ + void clear(); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + void deleteLayer(Layer* layer); + + struct LayerEntry { + LayerEntry(): + mLayer(NULL), mWidth(0), mHeight(0) { + } + + LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) { + mWidth = uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); + mHeight = uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); + } + + LayerEntry(const LayerEntry& entry): + mLayer(entry.mLayer), mWidth(entry.mWidth), mHeight(entry.mHeight) { + } + + LayerEntry(Layer* layer): + mLayer(layer), mWidth(layer->width), mHeight(layer->height) { + } + + bool operator<(const LayerEntry& rhs) const { + if (mWidth == rhs.mWidth) { + return mHeight < rhs.mHeight; + } + return mWidth < rhs.mWidth; + } + + bool operator==(const LayerEntry& rhs) const { + return mWidth == rhs.mWidth && mHeight == rhs.mHeight; + } + + Layer* mLayer; + uint32_t mWidth; + uint32_t mHeight; + }; // struct LayerEntry + + SortedList<LayerEntry> mCache; + + uint32_t mSize; + uint32_t mMaxSize; +}; // class LayerCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_LAYER_CACHE_H diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h new file mode 100644 index 0000000..64bdd6a --- /dev/null +++ b/libs/hwui/Line.h @@ -0,0 +1,130 @@ +/* + * 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_UI_LINE_H +#define ANDROID_UI_LINE_H + +#include <GLES2/gl2.h> + +#include <cmath> + +#include <sys/types.h> + +#include "Patch.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Globals +/////////////////////////////////////////////////////////////////////////////// + +// Alpha8 texture used to perform texture anti-aliasing +static const uint8_t gLineTexture[] = { + 0, 0, 0, 0, 0, + 0, 255, 255, 255, 0, + 0, 255, 255, 255, 0, + 0, 255, 255, 255, 0, + 0, 0, 0, 0, 0 +}; +static const GLsizei gLineTextureWidth = 5; +static const GLsizei gLineTextureHeight = 5; +static const float gLineAABias = 1.0f; + +/////////////////////////////////////////////////////////////////////////////// +// Line +/////////////////////////////////////////////////////////////////////////////// + +class Line { +public: + Line(): mXDivsCount(2), mYDivsCount(2) { + mPatch = new Patch(mXDivsCount, mYDivsCount); + mXDivs = new int32_t[mXDivsCount]; + mYDivs = new int32_t[mYDivsCount]; + + mXDivs[0] = mYDivs[0] = 2; + mXDivs[1] = mYDivs[1] = 3; + + glGenTextures(1, &mTexture); + glBindTexture(GL_TEXTURE_2D, mTexture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gLineTextureWidth, gLineTextureHeight, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, gLineTexture); + } + + ~Line() { + delete mPatch; + delete[] mXDivs; + delete[] mYDivs; + + glDeleteTextures(1, &mTexture); + } + + inline float getLength(float x1, float y1, float x2, float y2) { + return sqrtf((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + } + + void update(float x1, float y1, float x2, float y2, float lineWidth, float& tx, float& ty) { + const float length = getLength(x1, y1, x2, y2); + const float half = lineWidth * 0.5f; + + mPatch->updateVertices(gLineTextureWidth, gLineTextureHeight, + -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias, + mXDivs, mYDivs, mXDivsCount, mYDivsCount); + + tx = -gLineAABias; + ty = lineWidth <= 1.0f ? -gLineAABias : -half - gLineAABias; + } + + inline GLvoid* getVertices() const { + return &mPatch->vertices[0].position[0]; + } + + inline GLvoid* getTexCoords() const { + return &mPatch->vertices[0].texture[0]; + } + + inline GLsizei getElementsCount() const { + return mPatch->verticesCount; + } + + inline GLuint getTexture() const { + return mTexture; + } + +private: + uint32_t mXDivsCount; + uint32_t mYDivsCount; + + int32_t* mXDivs; + int32_t* mYDivs; + + Patch* mPatch; + + GLuint mTexture; +}; // class Line + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_LINE_H diff --git a/libs/hwui/MODULE_LICENSE_APACHE2 b/libs/hwui/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/hwui/MODULE_LICENSE_APACHE2 diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp new file mode 100644 index 0000000..5502e66 --- /dev/null +++ b/libs/hwui/Matrix.cpp @@ -0,0 +1,321 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include <utils/Log.h> + +#include <SkMatrix.h> + +#include "utils/Compare.h" +#include "Matrix.h" + +namespace android { +namespace uirenderer { + +void Matrix4::loadIdentity() { + data[kScaleX] = 1.0f; + data[kSkewY] = 0.0f; + data[2] = 0.0f; + data[kPerspective0] = 0.0f; + + data[kSkewX] = 0.0f; + data[kScaleY] = 1.0f; + data[6] = 0.0f; + data[kPerspective1] = 0.0f; + + data[8] = 0.0f; + data[9] = 0.0f; + data[kScaleZ] = 1.0f; + data[11] = 0.0f; + + data[kTranslateX] = 0.0f; + data[kTranslateY] = 0.0f; + data[kTranslateZ] = 0.0f; + data[kPerspective2] = 1.0f; + + mSimpleMatrix = true; +} + +bool Matrix4::changesBounds() { + return !(almost(data[0], 1.0f) && almost(data[1], 0.0f) && almost(data[2], 0.0f) && + almost(data[4], 0.0f) && almost(data[5], 1.0f) && almost(data[6], 0.0f) && + almost(data[8], 0.0f) && almost(data[9], 0.0f) && almost(data[10], 1.0f)); +} + +void Matrix4::load(const float* v) { + memcpy(data, v, sizeof(data)); + mSimpleMatrix = false; +} + +void Matrix4::load(const Matrix4& v) { + memcpy(data, v.data, sizeof(data)); + mSimpleMatrix = v.mSimpleMatrix; +} + +void Matrix4::load(const SkMatrix& v) { + memset(data, 0, sizeof(data)); + + data[kScaleX] = v[SkMatrix::kMScaleX]; + data[kSkewX] = v[SkMatrix::kMSkewX]; + data[kTranslateX] = v[SkMatrix::kMTransX]; + + data[kSkewY] = v[SkMatrix::kMSkewY]; + data[kScaleY] = v[SkMatrix::kMScaleY]; + data[kTranslateY] = v[SkMatrix::kMTransY]; + + data[kPerspective0] = v[SkMatrix::kMPersp0]; + data[kPerspective1] = v[SkMatrix::kMPersp1]; + data[kPerspective2] = v[SkMatrix::kMPersp2]; + + data[kScaleZ] = 1.0f; + + mSimpleMatrix = (v.getType() <= SkMatrix::kScale_Mask); +} + +void Matrix4::copyTo(SkMatrix& v) const { + v.reset(); + + v.set(SkMatrix::kMScaleX, data[kScaleX]); + v.set(SkMatrix::kMSkewX, data[kSkewX]); + v.set(SkMatrix::kMTransX, data[kTranslateX]); + + v.set(SkMatrix::kMSkewY, data[kSkewY]); + v.set(SkMatrix::kMScaleY, data[kScaleY]); + v.set(SkMatrix::kMTransY, data[kTranslateY]); + + v.set(SkMatrix::kMPersp0, data[kPerspective0]); + v.set(SkMatrix::kMPersp1, data[kPerspective1]); + v.set(SkMatrix::kMPersp2, data[kPerspective2]); +} + +void Matrix4::loadInverse(const Matrix4& v) { + double scale = 1.0 / + (v.data[kScaleX] * ((double) v.data[kScaleY] * v.data[kPerspective2] - + (double) v.data[kTranslateY] * v.data[kPerspective1]) + + v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] - + (double) v.data[kSkewY] * v.data[kPerspective2]) + + v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] - + (double) v.data[kScaleY] * v.data[kPerspective0])); + + data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] - + v.data[kTranslateY] * v.data[kPerspective1]) * scale; + data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] - + v.data[kSkewX] * v.data[kPerspective2]) * scale; + data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] - + v.data[kTranslateX] * v.data[kScaleY]) * scale; + + data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] - + v.data[kSkewY] * v.data[kPerspective2]) * scale; + data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] - + v.data[kTranslateX] * v.data[kPerspective0]) * scale; + data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] - + v.data[kScaleX] * v.data[kTranslateY]) * scale; + + data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] - + v.data[kScaleY] * v.data[kPerspective0]) * scale; + data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] - + v.data[kScaleX] * v.data[kPerspective1]) * scale; + data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] - + v.data[kSkewX] * v.data[kSkewY]) * scale; + + mSimpleMatrix = v.mSimpleMatrix; +} + +void Matrix4::copyTo(float* v) const { + memcpy(v, data, sizeof(data)); +} + +float Matrix4::getTranslateX() { + return data[kTranslateX]; +} + +float Matrix4::getTranslateY() { + return data[kTranslateY]; +} + +void Matrix4::multiply(float v) { + for (int i = 0; i < 16; i++) { + data[i] *= v; + } +} + +void Matrix4::loadTranslate(float x, float y, float z) { + loadIdentity(); + data[kTranslateX] = x; + data[kTranslateY] = y; + data[kTranslateZ] = z; +} + +void Matrix4::loadScale(float sx, float sy, float sz) { + loadIdentity(); + data[kScaleX] = sx; + data[kScaleY] = sy; + data[kScaleZ] = sz; +} + +void Matrix4::loadRotate(float angle, float x, float y, float z) { + data[kPerspective0] = 0.0f; + data[kPerspective1] = 0.0f; + data[11] = 0.0f; + data[kTranslateX] = 0.0f; + data[kTranslateY] = 0.0f; + data[kTranslateZ] = 0.0f; + data[kPerspective2] = 1.0f; + + angle *= float(M_PI / 180.0f); + float c = cosf(angle); + float s = sinf(angle); + + const float length = sqrtf(x * x + y * y + z * z); + float recipLen = 1.0f / length; + 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; + + data[kScaleX] = x * x * nc + c; + data[kSkewX] = xy * nc - zs; + data[8] = zx * nc + ys; + data[kSkewY] = xy * nc + zs; + data[kScaleY] = y * y * nc + c; + data[9] = yz * nc - xs; + data[2] = zx * nc - ys; + data[6] = yz * nc + xs; + data[kScaleZ] = z * z * nc + c; + + mSimpleMatrix = false; +} + +void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) { + for (int i = 0 ; i < 4 ; i++) { + float x = 0; + float y = 0; + float z = 0; + float w = 0; + + for (int j = 0 ; j < 4 ; j++) { + const float e = v.get(i, j); + x += u.get(j, 0) * e; + y += u.get(j, 1) * e; + z += u.get(j, 2) * e; + w += u.get(j, 3) * e; + } + + set(i, 0, x); + set(i, 1, y); + set(i, 2, z); + set(i, 3, w); + } + + mSimpleMatrix = u.mSimpleMatrix && v.mSimpleMatrix; +} + +void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) { + loadIdentity(); + data[kScaleX] = 2.0f / (right - left); + data[kScaleY] = 2.0f / (top - bottom); + data[kScaleZ] = -2.0f / (far - near); + data[kTranslateX] = -(right + left) / (right - left); + data[kTranslateY] = -(top + bottom) / (top - bottom); + data[kTranslateZ] = -(far + near) / (far - near); +} + +#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c) + +void Matrix4::mapPoint(float& x, float& y) const { + if (mSimpleMatrix) { + MUL_ADD_STORE(x, data[kScaleX], data[kTranslateX]); + MUL_ADD_STORE(y, data[kScaleY], data[kTranslateY]); + return; + } + + float dx = x * data[kScaleX] + y * data[kSkewX] + data[kTranslateX]; + float dy = x * data[kSkewY] + y * data[kScaleY] + data[kTranslateY]; + float dz = x * data[kPerspective0] + y * data[kPerspective1] + data[kPerspective2]; + if (dz) dz = 1.0f / dz; + + x = dx * dz; + y = dy * dz; +} + +void Matrix4::mapRect(Rect& r) const { + if (mSimpleMatrix) { + MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]); + MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]); + MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]); + MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]); + return; + } + + float vertices[] = { + r.left, r.top, + r.right, r.top, + r.right, r.bottom, + r.left, r.bottom + }; + + float x, y, z; + + for (int i = 0; i < 8; i+= 2) { + float px = vertices[i]; + float py = vertices[i + 1]; + + x = px * data[kScaleX] + py * data[kSkewX] + data[kTranslateX]; + y = px * data[kSkewY] + py * data[kScaleY] + data[kTranslateY]; + z = px * data[kPerspective0] + py * data[kPerspective1] + data[kPerspective2]; + if (z) z = 1.0f / z; + + vertices[i] = x * z; + vertices[i + 1] = y * z; + } + + r.left = r.right = vertices[0]; + r.top = r.bottom = vertices[1]; + + for (int i = 2; i < 8; i += 2) { + x = vertices[i]; + y = vertices[i + 1]; + + if (x < r.left) r.left = x; + else if (x > r.right) r.right = x; + if (y < r.top) r.top = y; + else if (y > r.bottom) r.bottom = y; + } +} + +void Matrix4::dump() const { + LOGD("Matrix4[simple=%d", mSimpleMatrix); + LOGD(" %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]); + LOGD(" %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]); + LOGD(" %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]); + LOGD(" %f %f %f %f", data[kPerspective0], data[kPerspective1], data[11], data[kPerspective2]); + LOGD("]"); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h new file mode 100644 index 0000000..fe81159 --- /dev/null +++ b/libs/hwui/Matrix.h @@ -0,0 +1,140 @@ +/* + * 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_UI_MATRIX_H +#define ANDROID_UI_MATRIX_H + +#include <SkMatrix.h> + +#include "Rect.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Classes +/////////////////////////////////////////////////////////////////////////////// + +class Matrix4 { +public: + float data[16]; + + enum Entry { + kScaleX = 0, + kSkewY = 1, + kPerspective0 = 3, + kSkewX = 4, + kScaleY = 5, + kPerspective1 = 7, + kScaleZ = 10, + kTranslateX = 12, + kTranslateY = 13, + kTranslateZ = 14, + kPerspective2 = 15 + }; + + Matrix4() { + loadIdentity(); + } + + Matrix4(const float* v) { + load(v); + } + + Matrix4(const Matrix4& v) { + load(v); + } + + Matrix4(const SkMatrix& v) { + load(v); + } + + void loadIdentity(); + + void load(const float* v); + void load(const Matrix4& v); + void load(const SkMatrix& v); + + void loadInverse(const Matrix4& v); + + void loadTranslate(float x, float y, float z); + void loadScale(float sx, float sy, float sz); + void loadRotate(float angle, float x, float y, float z); + void loadMultiply(const Matrix4& u, const Matrix4& v); + + void loadOrtho(float left, float right, float bottom, float top, float near, float far); + + void multiply(const Matrix4& v) { + Matrix4 u; + u.loadMultiply(*this, v); + load(u); + } + + void multiply(float v); + + void translate(float x, float y, float z) { + Matrix4 u; + u.loadTranslate(x, y, z); + multiply(u); + } + + void scale(float sx, float sy, float sz) { + Matrix4 u; + u.loadScale(sx, sy, sz); + multiply(u); + } + + void rotate(float angle, float x, float y, float z) { + Matrix4 u; + u.loadRotate(angle, x, y, z); + multiply(u); + } + + bool changesBounds(); + + void copyTo(float* v) const; + void copyTo(SkMatrix& v) const; + + void mapRect(Rect& r) const; + void mapPoint(float& x, float& y) const; + + float getTranslateX(); + float getTranslateY(); + + void dump() const; + +private: + bool mSimpleMatrix; + + inline float get(int i, int j) const { + return data[i * 4 + j]; + } + + inline void set(int i, int j, float v) { + data[i * 4 + j] = v; + } +}; // class Matrix4 + +/////////////////////////////////////////////////////////////////////////////// +// Types +/////////////////////////////////////////////////////////////////////////////// + +typedef Matrix4 mat4; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_MATRIX_H diff --git a/libs/hwui/NOTICE b/libs/hwui/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/libs/hwui/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp new file mode 100644 index 0000000..d492e23 --- /dev/null +++ b/libs/hwui/OpenGLDebugRenderer.cpp @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <utils/StopWatch.h> + +#include "OpenGLDebugRenderer.h" + +namespace android { +namespace uirenderer { + +void OpenGLDebugRenderer::prepare(bool opaque) { + mPrimitivesCount = 0; + LOGD("========= Frame start ========="); + OpenGLRenderer::prepare(opaque); +} + +void OpenGLDebugRenderer::finish() { + LOGD("========= Frame end ========="); + LOGD("Primitives draw count = %d", mPrimitivesCount); + OpenGLRenderer::finish(); +} + +void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { + mPrimitivesCount++; + StopWatch w("composeLayer"); + return OpenGLRenderer::composeLayer(current, previous); +} + +int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags) { + mPrimitivesCount++; + StopWatch w("saveLayer"); + return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags); +} + +void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, + const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawBitmap"); + OpenGLRenderer::drawBitmap(bitmap, left, top, paint); +} + +void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, + const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawBitmapMatrix"); + OpenGLRenderer::drawBitmap(bitmap, matrix, paint); +} + +void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawBitmapRect"); + OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, + dstLeft, dstTop, dstRight, dstBottom, paint); +} + +void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawPatch"); + OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, + left, top, right, bottom, paint); +} + +void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) { + mPrimitivesCount++; + StopWatch w("drawColor"); + OpenGLRenderer::drawColor(color, mode); +} + +void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom, + const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawRect"); + OpenGLRenderer::drawRect(left, top, right, bottom, paint); +} + +void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawPath"); + OpenGLRenderer::drawPath(path, paint); +} + +void OpenGLDebugRenderer::drawLines(float* points, int count, const SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawLines"); + OpenGLRenderer::drawLines(points, count, paint); +} + +void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, + SkPaint* paint) { + mPrimitivesCount++; + StopWatch w("drawText"); + OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h new file mode 100644 index 0000000..4997ef3 --- /dev/null +++ b/libs/hwui/OpenGLDebugRenderer.h @@ -0,0 +1,69 @@ +/* + * 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_UI_OPENGL_DEBUG_RENDERER_H +#define ANDROID_UI_OPENGL_DEBUG_RENDERER_H + +#include "OpenGLRenderer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////// + +class OpenGLDebugRenderer: public OpenGLRenderer { +public: + OpenGLDebugRenderer(): mPrimitivesCount(0) { + } + + ~OpenGLDebugRenderer() { + } + + void prepare(bool opaque); + void finish(); + + int saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags); + + void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint); + void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint); + void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint); + void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint); + void drawColor(int color, SkXfermode::Mode mode); + void drawRect(float left, float top, float right, float bottom, const SkPaint* paint); + void drawPath(SkPath* path, SkPaint* paint); + void drawLines(float* points, int count, const SkPaint* paint); + void drawText(const char* text, int bytesCount, int count, float x, float y, + SkPaint* paint); + +protected: + void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); + +private: + uint32_t mPrimitivesCount; + +}; // class OpenGLDebugRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_OPENGL_DEBUG_RENDERER_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp new file mode 100644 index 0000000..81fa1ea --- /dev/null +++ b/libs/hwui/OpenGLRenderer.cpp @@ -0,0 +1,1366 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <SkCanvas.h> +#include <SkTypeface.h> + +#include <utils/Log.h> +#include <utils/StopWatch.h> + +#include "OpenGLRenderer.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define REQUIRED_TEXTURE_UNITS_COUNT 3 + +// Generates simple and textured vertices +#define FV(x, y, u, v) { { x, y }, { u, v } } + +#define RAD_TO_DEG (180.0f / 3.14159265f) +#define MIN_ANGLE 0.001f + +// TODO: This should be set in properties +#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) + +/////////////////////////////////////////////////////////////////////////////// +// Globals +/////////////////////////////////////////////////////////////////////////////// + +// This array is never used directly but used as a memcpy source in the +// OpenGLRenderer constructor +static const TextureVertex gMeshVertices[] = { + FV(0.0f, 0.0f, 0.0f, 0.0f), + FV(1.0f, 0.0f, 1.0f, 0.0f), + FV(0.0f, 1.0f, 0.0f, 1.0f), + FV(1.0f, 1.0f, 1.0f, 1.0f) +}; +static const GLsizei gMeshStride = sizeof(TextureVertex); +static const GLsizei gMeshCount = 4; + +/** + * Structure mapping Skia xfermodes to OpenGL blending factors. + */ +struct Blender { + SkXfermode::Mode mode; + GLenum src; + GLenum dst; +}; // 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::kSrc_Mode, GL_ONE, GL_ZERO }, + { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, + { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, + { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, + { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, + { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, + { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } +}; + +// This array contains the swapped version of each SkXfermode. For instance +// 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::kSrc_Mode, GL_ZERO, GL_ONE }, + { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, + { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, + { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, + { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, + { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, + { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } +}; + +static const GLenum gTextureUnits[] = { + GL_TEXTURE0, + GL_TEXTURE1, + GL_TEXTURE2 +}; + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { + mShader = NULL; + mColorFilter = NULL; + mHasShadow = false; + + memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); + + mFirstSnapshot = new Snapshot; + + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { + LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); + } + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); +} + +OpenGLRenderer::~OpenGLRenderer() { + // The context has already been destroyed at this point, do not call + // GL APIs. All GL state should be kept in Caches.h +} + +/////////////////////////////////////////////////////////////////////////////// +// Setup +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::setViewport(int width, int height) { + glViewport(0, 0, width, height); + mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); + + mWidth = width; + mHeight = height; + + mFirstSnapshot->height = height; + mFirstSnapshot->viewport.set(0, 0, width, height); +} + +void OpenGLRenderer::prepare(bool opaque) { + mSnapshot = new Snapshot(mFirstSnapshot, + SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + mSaveCount = 1; + + glViewport(0, 0, mWidth, mHeight); + + glDisable(GL_DITHER); + glDisable(GL_SCISSOR_TEST); + + if (!opaque) { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, mWidth, mHeight); + + mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); +} + +void OpenGLRenderer::finish() { +#if DEBUG_OPENGL + GLenum status = GL_NO_ERROR; + while ((status = glGetError()) != GL_NO_ERROR) { + LOGD("GL error from OpenGLRenderer: 0x%x", status); + } +#endif +} + +void OpenGLRenderer::acquireContext() { + if (mCaches.currentProgram) { + if (mCaches.currentProgram->isInUse()) { + mCaches.currentProgram->remove(); + mCaches.currentProgram = NULL; + } + } +} + +void OpenGLRenderer::releaseContext() { + glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); + + glEnable(GL_SCISSOR_TEST); + setScissorFromClip(); + + glDisable(GL_DITHER); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (mCaches.blend) { + glEnable(GL_BLEND); + glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); + glBlendEquation(GL_FUNC_ADD); + } else { + glDisable(GL_BLEND); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// State management +/////////////////////////////////////////////////////////////////////////////// + +int OpenGLRenderer::getSaveCount() const { + return mSaveCount; +} + +int OpenGLRenderer::save(int flags) { + return saveSnapshot(flags); +} + +void OpenGLRenderer::restore() { + if (mSaveCount > 1) { + restoreSnapshot(); + } +} + +void OpenGLRenderer::restoreToCount(int saveCount) { + if (saveCount < 1) saveCount = 1; + + while (mSaveCount > saveCount) { + restoreSnapshot(); + } +} + +int OpenGLRenderer::saveSnapshot(int flags) { + mSnapshot = new Snapshot(mSnapshot, flags); + return mSaveCount++; +} + +bool OpenGLRenderer::restoreSnapshot() { + bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; + bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; + bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; + + sp<Snapshot> current = mSnapshot; + sp<Snapshot> previous = mSnapshot->previous; + + if (restoreOrtho) { + Rect& r = previous->viewport; + glViewport(r.left, r.top, r.right, r.bottom); + mOrthoMatrix.load(current->orthoMatrix); + } + + mSaveCount--; + mSnapshot = previous; + + if (restoreLayer) { + composeLayer(current, previous); + } + + if (restoreClip) { + setScissorFromClip(); + } + + return restoreClip; +} + +/////////////////////////////////////////////////////////////////////////////// +// Layers +/////////////////////////////////////////////////////////////////////////////// + +int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags) { + const GLuint previousFbo = mSnapshot->fbo; + const int count = saveSnapshot(flags); + + int alpha = 255; + SkXfermode::Mode mode; + + if (p) { + alpha = p->getAlpha(); + if (!mExtensions.hasFramebufferFetch()) { + const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); + if (!isMode) { + // Assume SRC_OVER + mode = SkXfermode::kSrcOver_Mode; + } + } else { + mode = getXfermode(p->getXfermode()); + } + } else { + mode = SkXfermode::kSrcOver_Mode; + } + + if (!mSnapshot->previous->invisible) { + createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); + } + + return count; +} + +int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, int flags) { + if (alpha == 0xff) { + return saveLayer(left, top, right, bottom, NULL, flags); + } else { + SkPaint paint; + paint.setAlpha(alpha); + return saveLayer(left, top, right, bottom, &paint, flags); + } +} + +/** + * Layers are viewed by Skia are slightly different than layers in image editing + * programs (for instance.) When a layer is created, previously created layers + * and the frame buffer still receive every drawing command. For instance, if a + * layer is created and a shape intersecting the bounds of the layers and the + * framebuffer is draw, the shape will be drawn on both (unless the layer was + * created with the SkCanvas::kClipToLayer_SaveFlag flag.) + * + * A way to implement layers is to create an FBO for each layer, backed by an RGBA + * texture. Unfortunately, this is inefficient as it requires every primitive to + * be drawn n + 1 times, where n is the number of active layers. In practice this + * means, for every primitive: + * - Switch active frame buffer + * - Change viewport, clip and projection matrix + * - Issue the drawing + * + * Switching rendering target n + 1 times per drawn primitive is extremely costly. + * To avoid this, layers are implemented in a different way here, at least in the + * general case. FBOs are used, as an optimization, when the "clip to layer" flag + * is set. When this flag is set we can redirect all drawing operations into a + * single FBO. + * + * This implementation relies on the frame buffer being at least RGBA 8888. When + * a layer is created, only a texture is created, not an FBO. The content of the + * frame buffer contained within the layer's bounds is copied into this texture + * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame + * buffer and drawing continues as normal. This technique therefore treats the + * frame buffer as a scratch buffer for the layers. + * + * To compose the layers back onto the frame buffer, each layer texture + * (containing the original frame buffer data) is drawn as a simple quad over + * the frame buffer. The trick is that the quad is set as the composition + * destination in the blending equation, and the frame buffer becomes the source + * of the composition. + * + * Drawing layers with an alpha value requires an extra step before composition. + * An empty quad is drawn over the layer's region in the frame buffer. This quad + * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the + * quad is used to multiply the colors in the frame buffer. This is achieved by + * changing the GL blend functions for the GL_FUNC_ADD blend equation to + * GL_ZERO, GL_SRC_ALPHA. + * + * Because glCopyTexImage2D() can be slow, an alternative implementation might + * be use to draw a single clipped layer. The implementation described above + * is correct in every case. + * + * (1) The frame buffer is actually not cleared right away. To allow the GPU + * to potentially optimize series of calls to glCopyTexImage2D, the frame + * buffer is left untouched until the first drawing operation. Only when + * something actually gets drawn are the layers regions cleared. + */ +bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, + float right, float bottom, int alpha, SkXfermode::Mode mode, + int flags, GLuint previousFbo) { + LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); + LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); + + const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; + + // Window coordinates of the layer + Rect bounds(left, top, right, bottom); + if (!fboLayer) { + mSnapshot->transform->mapRect(bounds); + // Layers only make sense if they are in the framebuffer's bounds + bounds.intersect(*mSnapshot->clipRect); + bounds.snapToPixelBoundaries(); + } + + if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize || + bounds.getHeight() > mMaxTextureSize) { + snapshot->invisible = true; + } else { + // TODO: Should take the mode into account + snapshot->invisible = snapshot->previous->invisible || + (alpha <= ALPHA_THRESHOLD && fboLayer); + } + + // Bail out if we won't draw in this snapshot + if (snapshot->invisible) { + return false; + } + + glActiveTexture(GL_TEXTURE0); + + Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight()); + if (!layer) { + return false; + } + + layer->mode = mode; + layer->alpha = alpha; + layer->layer.set(bounds); + layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height), + bounds.getWidth() / float(layer->width), 0.0f); + + // Save the layer in the snapshot + snapshot->flags |= Snapshot::kFlagIsLayer; + snapshot->layer = layer; + + if (fboLayer) { + layer->fbo = mCaches.fboCache.get(); + + snapshot->flags |= Snapshot::kFlagIsFboLayer; + snapshot->fbo = layer->fbo; + snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); + snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); + snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); + snapshot->height = bounds.getHeight(); + snapshot->flags |= Snapshot::kFlagDirtyOrtho; + snapshot->orthoMatrix.load(mOrthoMatrix); + + // Bind texture to FBO + glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); + glBindTexture(GL_TEXTURE_2D, layer->texture); + + // Initialize the texture if needed + if (layer->empty) { + layer->empty = false; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + layer->texture, 0); + +#if DEBUG_LAYERS + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LOGE("Framebuffer incomplete (GL error code 0x%x)", status); + + glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); + glDeleteTextures(1, &layer->texture); + mCaches.fboCache.put(layer->fbo); + + delete layer; + + return false; + } +#endif + + // Clear the FBO + glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + setScissorFromClip(); + + // Change the ortho projection + glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); + mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f); + } else { + // Copy the framebuffer into the layer + glBindTexture(GL_TEXTURE_2D, layer->texture); + + if (layer->empty) { + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom, + layer->width, layer->height, 0); + layer->empty = false; + } else { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom, + bounds.getWidth(), bounds.getHeight()); + } + + // Enqueue the buffer coordinates to clear the corresponding region later + mLayers.push(new Rect(bounds)); + } + + return true; +} + +/** + * Read the documentation of createLayer() before doing anything in this method. + */ +void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { + if (!current->layer) { + LOGE("Attempting to compose a layer that does not exist"); + return; + } + + const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag; + + if (fboLayer) { + // Unbind current FBO and restore previous one + glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + } + + // Restore the clip from the previous snapshot + const Rect& clip = *previous->clipRect; + glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight()); + + Layer* layer = current->layer; + const Rect& rect = layer->layer; + + if (!fboLayer && layer->alpha < 255) { + drawColorRect(rect.left, rect.top, rect.right, rect.bottom, + layer->alpha << 24, SkXfermode::kDstIn_Mode, true); + } + + const Rect& texCoords = layer->texCoords; + resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); + + if (fboLayer) { + drawTextureRect(rect.left, rect.top, rect.right, rect.bottom, + layer->texture, layer->alpha / 255.0f, layer->mode, layer->blend); + } else { + drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, + 1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], + &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true); + } + + resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); + + if (fboLayer) { + // Detach the texture from the FBO + glBindFramebuffer(GL_FRAMEBUFFER, current->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + + // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed + mCaches.fboCache.put(current->fbo); + } + + // Failing to add the layer to the cache should happen only if the layer is too large + if (!mCaches.layerCache.put(layer)) { + LAYER_LOGD("Deleting layer"); + glDeleteTextures(1, &layer->texture); + delete layer; + } +} + +void OpenGLRenderer::clearLayerRegions() { + if (mLayers.size() == 0 || mSnapshot->invisible) return; + + for (uint32_t i = 0; i < mLayers.size(); i++) { + Rect* bounds = mLayers.itemAt(i); + + // Clear the framebuffer where the layer will draw + glScissor(bounds->left, mSnapshot->height - bounds->bottom, + bounds->getWidth(), bounds->getHeight()); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + delete bounds; + } + mLayers.clear(); + + // Restore the clip + setScissorFromClip(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Transforms +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::translate(float dx, float dy) { + mSnapshot->transform->translate(dx, dy, 0.0f); +} + +void OpenGLRenderer::rotate(float degrees) { + mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); +} + +void OpenGLRenderer::scale(float sx, float sy) { + mSnapshot->transform->scale(sx, sy, 1.0f); +} + +void OpenGLRenderer::setMatrix(SkMatrix* matrix) { + mSnapshot->transform->load(*matrix); +} + +const float* OpenGLRenderer::getMatrix() const { + if (mSnapshot->fbo != 0) { + return &mSnapshot->transform->data[0]; + } + return &mIdentity.data[0]; +} + +void OpenGLRenderer::getMatrix(SkMatrix* matrix) { + mSnapshot->transform->copyTo(*matrix); +} + +void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { + mat4 m(*matrix); + mSnapshot->transform->multiply(m); +} + +/////////////////////////////////////////////////////////////////////////////// +// Clipping +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::setScissorFromClip() { + const Rect& clip = *mSnapshot->clipRect; + glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); +} + +const Rect& OpenGLRenderer::getClipBounds() { + return mSnapshot->getLocalClip(); +} + +bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { + if (mSnapshot->invisible) { + return true; + } + + Rect r(left, top, right, bottom); + mSnapshot->transform->mapRect(r); + r.snapToPixelBoundaries(); + + Rect clipRect(*mSnapshot->clipRect); + clipRect.snapToPixelBoundaries(); + + return !clipRect.intersects(r); +} + +bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { + bool clipped = mSnapshot->clip(left, top, right, bottom, op); + if (clipped) { + setScissorFromClip(); + } + return !mSnapshot->clipRect->isEmpty(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Drawing +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) { + const float right = left + bitmap->width(); + const float bottom = top + bitmap->height(); + + if (quickReject(left, top, right, bottom)) { + return; + } + + glActiveTexture(GL_TEXTURE0); + const Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + drawTextureRect(left, top, right, bottom, texture, paint); +} + +void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) { + Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); + const mat4 transform(*matrix); + transform.mapRect(r); + + if (quickReject(r.left, r.top, r.right, r.bottom)) { + return; + } + + glActiveTexture(GL_TEXTURE0); + const Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint); +} + +void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, + float srcLeft, float srcTop, float srcRight, float srcBottom, + float dstLeft, float dstTop, float dstRight, float dstBottom, + const SkPaint* paint) { + if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { + return; + } + + glActiveTexture(GL_TEXTURE0); + const Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + 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; + + resetDrawTextureTexCoords(u1, v1, u2, v2); + + drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint); + + resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); +} + +void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint) { + if (quickReject(left, top, right, bottom)) { + return; + } + + glActiveTexture(GL_TEXTURE0); + const Texture* texture = mCaches.textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), + right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); + + // Specify right and bottom as +1.0f from left/top to prevent scaling since the + // patch mesh already defines the final size + drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f, + mode, texture->blend, &mesh->vertices[0].position[0], + &mesh->vertices[0].texture[0], GL_TRIANGLES, mesh->verticesCount); +} + +void OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) { + if (mSnapshot->invisible) return; + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + uint32_t color = paint->getColor(); + const GLfloat a = alpha / 255.0f; + const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; + const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; + const GLfloat b = a * ((color ) & 0xFF) / 255.0f; + + const bool isAA = paint->isAntiAlias(); + if (isAA) { + GLuint textureUnit = 0; + setupTextureAlpha8(mCaches.line.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a, + mode, false, true, mCaches.line.getVertices(), mCaches.line.getTexCoords()); + } else { + setupColorRect(0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a, mode, false); + } + + const float strokeWidth = paint->getStrokeWidth(); + const GLsizei elementsCount = isAA ? mCaches.line.getElementsCount() : gMeshCount; + const GLenum drawMode = isAA ? GL_TRIANGLES : GL_TRIANGLE_STRIP; + + for (int i = 0; i < count; i += 4) { + float tx = 0.0f; + float ty = 0.0f; + + if (isAA) { + mCaches.line.update(points[i], points[i + 1], points[i + 2], points[i + 3], + strokeWidth, tx, ty); + } else { + ty = strokeWidth <= 1.0f ? 0.0f : -strokeWidth * 0.5f; + } + + const float dx = points[i + 2] - points[i]; + const float dy = points[i + 3] - points[i + 1]; + const float mag = sqrtf(dx * dx + dy * dy); + const float angle = acos(dx / mag); + + mModelView.loadTranslate(points[i], points[i + 1], 0.0f); + if (angle > MIN_ANGLE || angle < -MIN_ANGLE) { + mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f); + } + mModelView.translate(tx, ty, 0.0f); + if (!isAA) { + float length = mCaches.line.getLength(points[i], points[i + 1], + points[i + 2], points[i + 3]); + mModelView.scale(length, strokeWidth, 1.0f); + } + mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); + + if (mShader) { + mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot); + } + + glDrawArrays(drawMode, 0, elementsCount); + } + + if (isAA) { + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); + } +} + +void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { + const Rect& clip = *mSnapshot->clipRect; + drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); +} + +void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { + if (quickReject(left, top, right, bottom)) { + return; + } + + SkXfermode::Mode mode; + if (!mExtensions.hasFramebufferFetch()) { + const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); + if (!isMode) { + // Assume SRC_OVER + mode = SkXfermode::kSrcOver_Mode; + } + } else { + mode = getXfermode(p->getXfermode()); + } + + // Skia draws using the color's alpha channel if < 255 + // Otherwise, it uses the paint's alpha + int color = p->getColor(); + if (((color >> 24) & 0xff) == 255) { + color |= p->getAlpha() << 24; + } + + drawColorRect(left, top, right, bottom, color, mode); +} + +void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, + float x, float y, SkPaint* paint) { + if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { + return; + } + if (mSnapshot->invisible) return; + + paint->setAntiAlias(true); + + float length = -1.0f; + switch (paint->getTextAlign()) { + case SkPaint::kCenter_Align: + length = paint->measureText(text, bytesCount); + x -= length / 2.0f; + break; + case SkPaint::kRight_Align: + length = paint->measureText(text, bytesCount); + x -= length; + break; + default: + break; + } + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + uint32_t color = paint->getColor(); + const GLfloat a = alpha / 255.0f; + const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; + const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; + const GLfloat b = a * ((color ) & 0xFF) / 255.0f; + + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), + paint->getTextSize()); + + if (mHasShadow) { + glActiveTexture(gTextureUnits[0]); + mCaches.dropShadowCache.setFontRenderer(fontRenderer); + const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, + count, mShadowRadius); + const AutoTexture autoCleanup(shadow); + + setupShadow(shadow, x, y, mode, a); + + // Draw the mesh + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); + } + + GLuint textureUnit = 0; + glActiveTexture(gTextureUnits[textureUnit]); + + // Assume that the modelView matrix does not force scales, rotates, etc. + const bool linearFilter = mSnapshot->transform->changesBounds(); + setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit, + x, y, r, g, b, a, mode, false, true); + + const Rect& clip = mSnapshot->getLocalClip(); + clearLayerRegions(); + fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); + + drawTextDecorations(text, bytesCount, length, x, y, paint); +} + +void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { + if (mSnapshot->invisible) return; + + GLuint textureUnit = 0; + glActiveTexture(gTextureUnits[textureUnit]); + + const PathTexture* texture = mCaches.pathCache.get(path, paint); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + const float x = texture->left - texture->offset; + const float y = texture->top - texture->offset; + + if (quickReject(x, y, x + texture->width, y + texture->height)) { + return; + } + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + uint32_t color = paint->getColor(); + const GLfloat a = alpha / 255.0f; + const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; + const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; + const GLfloat b = a * ((color ) & 0xFF) / 255.0f; + + setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true); + + clearLayerRegions(); + + // Draw the mesh + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); +} + +/////////////////////////////////////////////////////////////////////////////// +// Shaders +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::resetShader() { + mShader = NULL; +} + +void OpenGLRenderer::setupShader(SkiaShader* shader) { + mShader = shader; + if (mShader) { + mShader->set(&mCaches.textureCache, &mCaches.gradientCache); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Color filters +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::resetColorFilter() { + mColorFilter = NULL; +} + +void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { + mColorFilter = filter; +} + +/////////////////////////////////////////////////////////////////////////////// +// Drop shadow +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::resetShadow() { + mHasShadow = false; +} + +void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { + mHasShadow = true; + mShadowRadius = radius; + mShadowDx = dx; + mShadowDy = dy; + mShadowColor = color; +} + +/////////////////////////////////////////////////////////////////////////////// +// Drawing implementation +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, + SkXfermode::Mode mode, float alpha) { + const float sx = x - texture->left + mShadowDx; + const float sy = y - texture->top + mShadowDy; + + const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); + const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha; + const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f; + const GLfloat g = a * ((mShadowColor >> 8) & 0xFF) / 255.0f; + const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; + + GLuint textureUnit = 0; + setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); +} + +void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, + float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, + bool transforms, bool applyFilters) { + setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, + x, y, r, g, b, a, mode, transforms, applyFilters, + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); +} + +void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, + GLuint& textureUnit, float x, float y, float r, float g, float b, float a, + SkXfermode::Mode mode, bool transforms, bool applyFilters) { + setupTextureAlpha8(texture, width, height, textureUnit, + x, y, r, g, b, a, mode, transforms, applyFilters, + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); +} + +void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, + GLuint& textureUnit, float x, float y, float r, float g, float b, float a, + SkXfermode::Mode mode, bool transforms, bool applyFilters, + GLvoid* vertices, GLvoid* texCoords) { + // Describe the required shaders + ProgramDescription description; + description.hasTexture = true; + description.hasAlpha8Texture = true; + const bool setColor = description.setAlpha8Color(r, g, b, a); + + if (applyFilters) { + if (mShader) { + mShader->describe(description, mExtensions); + } + if (mColorFilter) { + mColorFilter->describe(description, mExtensions); + } + } + + // Setup the blending mode + chooseBlending(true, mode, description); + + // Build and use the appropriate shader + useProgram(mCaches.programCache.get(description)); + + bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit); + glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); + + int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); + glEnableVertexAttribArray(texCoordsSlot); + + // Setup attributes + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, + gMeshStride, vertices); + glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, + gMeshStride, texCoords); + + // Setup uniforms + if (transforms) { + mModelView.loadTranslate(x, y, 0.0f); + mModelView.scale(width, height, 1.0f); + } else { + mModelView.loadIdentity(); + } + mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); + if (setColor) { + mCaches.currentProgram->setColor(r, g, b, a); + } + + textureUnit++; + if (applyFilters) { + // Setup attributes and uniforms required by the shaders + if (mShader) { + mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); + } + if (mColorFilter) { + mColorFilter->setupProgram(mCaches.currentProgram); + } + } +} + +// Same values used by Skia +#define kStdStrikeThru_Offset (-6.0f / 21.0f) +#define kStdUnderline_Offset (1.0f / 9.0f) +#define kStdUnderline_Thickness (1.0f / 18.0f) + +void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, + float x, float y, SkPaint* paint) { + // Handle underline and strike-through + uint32_t flags = paint->getFlags(); + if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + 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); + } + + float offsetX = 0; + switch (paint->getTextAlign()) { + case SkPaint::kCenter_Align: + offsetX = underlineWidth * 0.5f; + break; + case SkPaint::kRight_Align: + offsetX = underlineWidth; + break; + default: + break; + } + + if (underlineWidth > 0.0f) { + const float textSize = paint->getTextSize(); + const float strokeWidth = textSize * kStdUnderline_Thickness; + + const float left = x - offsetX; + float top = 0.0f; + + const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1); + float points[pointsCount]; + int currentPoint = 0; + + if (flags & SkPaint::kUnderlineText_Flag) { + top = y + textSize * kStdUnderline_Offset; + points[currentPoint++] = left; + points[currentPoint++] = top; + points[currentPoint++] = left + underlineWidth; + points[currentPoint++] = top; + } + + if (flags & SkPaint::kStrikeThruText_Flag) { + top = y + textSize * kStdStrikeThru_Offset; + points[currentPoint++] = left; + points[currentPoint++] = top; + points[currentPoint++] = left + underlineWidth; + points[currentPoint++] = top; + } + + SkPaint linesPaint(*paint); + linesPaint.setStrokeWidth(strokeWidth); + + drawLines(&points[0], pointsCount, &linesPaint); + } + } +} + +void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, + int color, SkXfermode::Mode mode, bool ignoreTransform) { + clearLayerRegions(); + + // If a shader is set, preserve only the alpha + if (mShader) { + color |= 0x00ffffff; + } + + // Render using pre-multiplied alpha + const int alpha = (color >> 24) & 0xFF; + const GLfloat a = alpha / 255.0f; + const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; + const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; + const GLfloat b = a * ((color ) & 0xFF) / 255.0f; + + setupColorRect(left, top, right, bottom, r, g, b, a, mode, ignoreTransform); + + // Draw the mesh + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); +} + +void OpenGLRenderer::setupColorRect(float left, float top, float right, float bottom, + float r, float g, float b, float a, SkXfermode::Mode mode, bool ignoreTransform) { + GLuint textureUnit = 0; + + // Describe the required shaders + ProgramDescription description; + const bool setColor = description.setColor(r, g, b, a); + + if (mShader) { + mShader->describe(description, mExtensions); + } + if (mColorFilter) { + mColorFilter->describe(description, mExtensions); + } + + // Setup the blending mode + chooseBlending(a < 1.0f || (mShader && mShader->blend()), mode, description); + + // Build and use the appropriate shader + useProgram(mCaches.programCache.get(description)); + + // Setup attributes + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, + gMeshStride, &mMeshVertices[0].position[0]); + + // Setup uniforms + mModelView.loadTranslate(left, top, 0.0f); + mModelView.scale(right - left, bottom - top, 1.0f); + if (!ignoreTransform) { + mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); + } else { + mat4 identity; + mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); + } + mCaches.currentProgram->setColor(r, g, b, a); + + // Setup attributes and uniforms required by the shaders + if (mShader) { + mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); + } + if (mColorFilter) { + mColorFilter->setupProgram(mCaches.currentProgram); + } +} + +void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, + const Texture* texture, const SkPaint* paint) { + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, + texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], + GL_TRIANGLE_STRIP, gMeshCount); +} + +void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, + GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { + drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, + &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], + GL_TRIANGLE_STRIP, gMeshCount); +} + +void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, + GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, + GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, + bool swapSrcDst, bool ignoreTransform) { + clearLayerRegions(); + + ProgramDescription description; + description.hasTexture = true; + const bool setColor = description.setColor(alpha, alpha, alpha, alpha); + if (mColorFilter) { + mColorFilter->describe(description, mExtensions); + } + + mModelView.loadTranslate(left, top, 0.0f); + mModelView.scale(right - left, bottom - top, 1.0f); + + chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst); + + useProgram(mCaches.programCache.get(description)); + if (!ignoreTransform) { + mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); + } else { + mat4 m; + mCaches.currentProgram->set(mOrthoMatrix, mModelView, m); + } + + // Texture + bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); + glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); + + // Always premultiplied + if (setColor) { + mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); + } + + // Mesh + int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); + glEnableVertexAttribArray(texCoordsSlot); + glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, + gMeshStride, vertices); + glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); + + // Color filter + if (mColorFilter) { + mColorFilter->setupProgram(mCaches.currentProgram); + } + + glDrawArrays(drawMode, 0, elementsCount); + glDisableVertexAttribArray(texCoordsSlot); +} + +void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, + ProgramDescription& description, bool swapSrcDst) { + blend = blend || mode != SkXfermode::kSrcOver_Mode; + if (blend) { + if (mode < SkXfermode::kPlus_Mode) { + if (!mCaches.blend) { + glEnable(GL_BLEND); + } + + GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; + GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; + + if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { + glBlendFunc(sourceMode, destMode); + mCaches.lastSrcMode = sourceMode; + mCaches.lastDstMode = destMode; + } + } else { + // These blend modes are not supported by OpenGL directly and have + // to be implemented using shaders. Since the shader will perform + // the blending, turn blending off here + if (mExtensions.hasFramebufferFetch()) { + description.framebufferMode = mode; + description.swapSrcDst = swapSrcDst; + } + + if (mCaches.blend) { + glDisable(GL_BLEND); + } + blend = false; + } + } else if (mCaches.blend) { + glDisable(GL_BLEND); + } + mCaches.blend = blend; +} + +bool OpenGLRenderer::useProgram(Program* program) { + if (!program->isInUse()) { + if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); + program->use(); + mCaches.currentProgram = program; + return false; + } + return true; +} + +void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { + TextureVertex* v = &mMeshVertices[0]; + TextureVertex::setUV(v++, u1, v1); + TextureVertex::setUV(v++, u2, v1); + TextureVertex::setUV(v++, u1, v2); + TextureVertex::setUV(v++, u2, v2); +} + +void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { + if (paint) { + if (!mExtensions.hasFramebufferFetch()) { + const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); + if (!isMode) { + // Assume SRC_OVER + *mode = SkXfermode::kSrcOver_Mode; + } + } else { + *mode = getXfermode(paint->getXfermode()); + } + + // Skia draws using the color's alpha channel if < 255 + // Otherwise, it uses the paint's alpha + int color = paint->getColor(); + *alpha = (color >> 24) & 0xFF; + if (*alpha == 255) { + *alpha = paint->getAlpha(); + } + } else { + *mode = SkXfermode::kSrcOver_Mode; + *alpha = 255; + } +} + +SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { + if (mode == NULL) { + return SkXfermode::kSrcOver_Mode; + } + return mode->fMode; +} + +void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { + glActiveTexture(gTextureUnits[textureUnit]); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h new file mode 100644 index 0000000..423614b --- /dev/null +++ b/libs/hwui/OpenGLRenderer.h @@ -0,0 +1,445 @@ +/* + * 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_UI_OPENGL_RENDERER_H +#define ANDROID_UI_OPENGL_RENDERER_H + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <SkBitmap.h> +#include <SkMatrix.h> +#include <SkPaint.h> +#include <SkRegion.h> +#include <SkShader.h> +#include <SkXfermode.h> + +#include <utils/RefBase.h> +#include <utils/Vector.h> + +#include "Extensions.h" +#include "Matrix.h" +#include "Program.h" +#include "Rect.h" +#include "Snapshot.h" +#include "Vertex.h" +#include "SkiaShader.h" +#include "SkiaColorFilter.h" +#include "Caches.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#define DEBUG_OPENGL 1 + +/////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////// + +class DisplayListRenderer; + +/** + * OpenGL renderer used to draw accelerated 2D graphics. The API is a + * simplified version of Skia's Canvas API. + */ +class OpenGLRenderer { +public: + OpenGLRenderer(); + virtual ~OpenGLRenderer(); + + virtual void setViewport(int width, int height); + + virtual void prepare(bool opaque); + virtual void finish(); + + virtual void acquireContext(); + virtual void releaseContext(); + + int getSaveCount() const; + virtual int save(int flags); + virtual void restore(); + virtual void restoreToCount(int saveCount); + + virtual int saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags); + virtual int saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, int flags); + + virtual void translate(float dx, float dy); + virtual void rotate(float degrees); + virtual void scale(float sx, float sy); + + const float* getMatrix() const; + void getMatrix(SkMatrix* matrix); + virtual void setMatrix(SkMatrix* matrix); + virtual void concatMatrix(SkMatrix* matrix); + + const Rect& getClipBounds(); + bool quickReject(float left, float top, float right, float bottom); + virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); + + virtual void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint); + virtual void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint); + virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, + float dstRight, float dstBottom, const SkPaint* paint); + virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, + const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, + float left, float top, float right, float bottom, const SkPaint* paint); + virtual void drawColor(int color, SkXfermode::Mode mode); + virtual void drawRect(float left, float top, float right, float bottom, const SkPaint* paint); + virtual void drawPath(SkPath* path, SkPaint* paint); + virtual void drawLines(float* points, int count, const SkPaint* paint); + virtual void drawText(const char* text, int bytesCount, int count, float x, float y, + SkPaint* paint); + + virtual void resetShader(); + virtual void setupShader(SkiaShader* shader); + + virtual void resetColorFilter(); + virtual void setupColorFilter(SkiaColorFilter* filter); + + virtual void resetShadow(); + virtual void setupShadow(float radius, float dx, float dy, int color); + +protected: + /** + * Compose the layer defined in the current snapshot with the layer + * defined by the previous snapshot. + * + * The current snapshot *must* be a layer (flag kFlagIsLayer set.) + * + * @param curent The current snapshot containing the layer to compose + * @param previous The previous snapshot to compose the current layer with + */ + virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); + +private: + /** + * Saves the current state of the renderer as a new snapshot. + * The new snapshot is saved in mSnapshot and the previous snapshot + * is linked from mSnapshot->previous. + * + * @param flags The save flags; see SkCanvas for more information + * + * @return The new save count. This value can be passed to #restoreToCount() + */ + int saveSnapshot(int flags); + + /** + * Restores the current snapshot; mSnapshot becomes mSnapshot->previous. + * + * @return True if the clip was modified. + */ + bool restoreSnapshot(); + + /** + * Sets the clipping rectangle using glScissor. The clip is defined by + * the current snapshot's clipRect member. + */ + void setScissorFromClip(); + + /** + * Creates a new layer stored in the specified snapshot. + * + * @param snapshot The snapshot associated with the new layer + * @param left The left coordinate of the layer + * @param top The top coordinate of the layer + * @param right The right coordinate of the layer + * @param bottom The bottom coordinate of the layer + * @param alpha The translucency of the layer + * @param mode The blending mode of the layer + * @param flags The layer save flags + * @param previousFbo The name of the current framebuffer + * + * @return True if the layer was successfully created, false otherwise + */ + bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, + int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo); + + /** + * Clears all the regions corresponding to the current list of layers. + * This method MUST be invoked before any drawing operation. + */ + void clearLayerRegions(); + + /** + * Draws a colored rectangle with the specified color. The specified coordinates + * are transformed by the current snapshot's transform matrix. + * + * @param left The left coordinate of the rectangle + * @param top The top coordinate of the rectangle + * @param right The right coordinate of the rectangle + * @param bottom The bottom coordinate of the rectangle + * @param color The rectangle's ARGB color, defined as a packed 32 bits word + * @param mode The Skia xfermode to use + * @param ignoreTransform True if the current transform should be ignored + * @paran ignoreBlending True if the blending is set by the caller + */ + void drawColorRect(float left, float top, float right, float bottom, + int color, SkXfermode::Mode mode, bool ignoreTransform = false); + + /** + * Setups shaders to draw a colored rect. + */ + void setupColorRect(float left, float top, float right, float bottom, + float r, float g, float b, float a, SkXfermode::Mode mode, bool ignoreTransform); + + /** + * Draws a textured rectangle with the specified texture. The specified coordinates + * are transformed by the current snapshot's transform matrix. + * + * @param left The left coordinate of the rectangle + * @param top The top coordinate of the rectangle + * @param right The right coordinate of the rectangle + * @param bottom The bottom coordinate of the rectangle + * @param texture The texture name to map onto the rectangle + * @param alpha An additional translucency parameter, between 0.0f and 1.0f + * @param mode The blending mode + * @param blend True if the texture contains an alpha channel + */ + void drawTextureRect(float left, float top, float right, float bottom, GLuint texture, + float alpha, SkXfermode::Mode mode, bool blend); + + /** + * Draws a textured rectangle with the specified texture. The specified coordinates + * are transformed by the current snapshot's transform matrix. + * + * @param left The left coordinate of the rectangle + * @param top The top coordinate of the rectangle + * @param right The right coordinate of the rectangle + * @param bottom The bottom coordinate of the rectangle + * @param texture The texture to use + * @param paint The paint containing the alpha, blending mode, etc. + */ + void drawTextureRect(float left, float top, float right, float bottom, + const Texture* texture, const SkPaint* paint); + + /** + * Draws a textured mesh with the specified texture. If the indices are omitted, the + * mesh is drawn as a simple quad. + * + * @param left The left coordinate of the rectangle + * @param top The top coordinate of the rectangle + * @param right The right coordinate of the rectangle + * @param bottom The bottom coordinate of the rectangle + * @param texture The texture name to map onto the rectangle + * @param alpha An additional translucency parameter, between 0.0f and 1.0f + * @param mode The blending mode + * @param blend True if the texture contains an alpha channel + * @param vertices The vertices that define the mesh + * @param texCoords The texture coordinates of each vertex + * @param indices The indices of the vertices, can be NULL + * @param elementsCount The number of elements in the mesh, required by indices + * @param swapSrcDst Whether or not the src and dst blending operations should be swapped + * @param ignoreTransform True if the current transform should be ignored + */ + void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture, + float alpha, SkXfermode::Mode mode, bool blend, + GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, + bool swapSrcDst = false, bool ignoreTransform = false); + + /** + * Prepares the renderer to draw the specified shadow. + * + * @param texture The shadow texture + * @param x The x coordinate of the shadow + * @param y The y coordinate of the shadow + * @param mode The blending mode + * @param alpha The alpha value + */ + void setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode, + float alpha); + + /** + * Prepares the renderer to draw the specified Alpha8 texture as a rectangle. + * + * @param texture The texture to render with + * @param textureUnit The texture unit to use, may be modified + * @param x The x coordinate of the rectangle to draw + * @param y The y coordinate of the rectangle to draw + * @param r The red component of the color + * @param g The green component of the color + * @param b The blue component of the color + * @param a The alpha component of the color + * @param mode The blending mode + * @param transforms True if the matrix passed to the shader should be multiplied + * by the model-view matrix + * @param applyFilters Whether or not to take color filters and + * shaders into account + */ + void setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, float x, float y, + float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms, + bool applyFilters); + + /** + * Prepares the renderer to draw the specified Alpha8 texture as a rectangle. + * + * @param texture The texture to render with + * @param width The width of the texture + * @param height The height of the texture + * @param textureUnit The texture unit to use, may be modified + * @param x The x coordinate of the rectangle to draw + * @param y The y coordinate of the rectangle to draw + * @param r The red component of the color + * @param g The green component of the color + * @param b The blue component of the color + * @param a The alpha component of the color + * @param mode The blending mode + * @param transforms True if the matrix passed to the shader should be multiplied + * by the model-view matrix + * @param applyFilters Whether or not to take color filters and + * shaders into account + */ + void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, + GLuint& textureUnit, float x, float y, float r, float g, float b, float a, + SkXfermode::Mode mode, bool transforms, bool applyFilters); + + /** + * Same as above setupTextureAlpha8() but specifies the mesh's vertices + * and texCoords pointers. + */ + void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, + GLuint& textureUnit, float x, float y, float r, float g, float b, float a, + SkXfermode::Mode mode, bool transforms, bool applyFilters, + GLvoid* vertices, GLvoid* texCoords); + + /** + * Draws text underline and strike-through if needed. + * + * @param text The text to decor + * @param bytesCount The number of bytes in the text + * @param length The length in pixels of the text, can be <= 0.0f to force a measurement + * @param x The x coordinate where the text will be drawn + * @param y The y coordinate where the text will be drawn + * @param paint The paint to draw the text with + */ + void drawTextDecorations(const char* text, int bytesCount, float length, + float x, float y, SkPaint* paint); + + /** + * Resets the texture coordinates stored in mMeshVertices. Setting the values + * back to default is achieved by calling: + * + * resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); + * + * @param u1 The left coordinate of the texture + * @param v1 The bottom coordinate of the texture + * @param u2 The right coordinate of the texture + * @param v2 The top coordinate of the texture + */ + void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2); + + /** + * Gets the alpha and xfermode out of a paint object. If the paint is null + * alpha will be 255 and the xfermode will be SRC_OVER. + * + * @param paint The paint to extract values from + * @param alpha Where to store the resulting alpha + * @param mode Where to store the resulting xfermode + */ + inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode); + + /** + * Binds the specified texture with the specified wrap modes. + */ + inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit = 0); + + /** + * Enable or disable blending as necessary. This function sets the appropriate + * blend function based on the specified xfermode. + */ + inline void chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, + bool swapSrcDst = false); + + /** + * Safely retrieves the mode from the specified xfermode. If the specified + * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode. + */ + inline SkXfermode::Mode getXfermode(SkXfermode* mode); + + /** + * Use the specified program with the current GL context. If the program is already + * in use, it will not be bound again. If it is not in use, the current program is + * marked unused and the specified program becomes used and becomes the new + * current program. + * + * @param program The program to use + * + * @return true If the specified program was already in use, false otherwise. + */ + inline bool useProgram(Program* program); + + // Dimensions of the drawing surface + int mWidth, mHeight; + + // Matrix used for ortho projection in shaders + mat4 mOrthoMatrix; + + // Model-view matrix used to position/size objects + mat4 mModelView; + + // Number of saved states + int mSaveCount; + // Base state + sp<Snapshot> mFirstSnapshot; + // Current state + sp<Snapshot> mSnapshot; + + // Shaders + SkiaShader* mShader; + + // Color filters + SkiaColorFilter* mColorFilter; + + // Used to draw textured quads + TextureVertex mMeshVertices[4]; + + // GL extensions + Extensions mExtensions; + + // Drop shadow + bool mHasShadow; + float mShadowRadius; + float mShadowDx; + float mShadowDy; + int mShadowColor; + + // Various caches + Caches& mCaches; + + // List of rectangles to clear due to calls to saveLayer() + Vector<Rect*> mLayers; + + // Misc + GLint mMaxTextureSize; + + // Indentity matrix + const mat4 mIdentity; + + friend class DisplayListRenderer; + +}; // class OpenGLRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_OPENGL_RENDERER_H diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp new file mode 100644 index 0000000..560decf --- /dev/null +++ b/libs/hwui/Patch.cpp @@ -0,0 +1,163 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <cmath> + +#include <utils/Log.h> + +#include "Patch.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads) { + // 2 triangles per patch, 3 vertices per triangle + verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3; + vertices = new TextureVertex[verticesCount]; +} + +Patch::~Patch() { + delete[] vertices; +} + +/////////////////////////////////////////////////////////////////////////////// +// Vertices management +/////////////////////////////////////////////////////////////////////////////// + +void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, + float left, float top, float right, float bottom, + const int32_t* xDivs, const int32_t* yDivs, + const uint32_t width, const uint32_t height, const uint32_t colorKey) { + const uint32_t xStretchCount = (width + 1) >> 1; + const uint32_t yStretchCount = (height + 1) >> 1; + + float stretchX = 0.0f; + float stretchY = 0.0; + + const float meshWidth = right - left; + + if (xStretchCount > 0) { + uint32_t stretchSize = 0; + for (uint32_t i = 1; i < width; i += 2) { + stretchSize += xDivs[i] - xDivs[i - 1]; + } + const float xStretchTex = stretchSize; + const float fixed = bitmapWidth - stretchSize; + const float xStretch = right - left - fixed; + stretchX = xStretch / xStretchTex; + } + + if (yStretchCount > 0) { + uint32_t stretchSize = 0; + for (uint32_t i = 1; i < height; i += 2) { + stretchSize += yDivs[i] - yDivs[i - 1]; + } + const float yStretchTex = stretchSize; + const float fixed = bitmapHeight - stretchSize; + const float yStretch = bottom - top - fixed; + stretchY = yStretch / yStretchTex; + } + + TextureVertex* vertex = vertices; + uint32_t quadCount = 0; + + float previousStepY = 0.0f; + + float y1 = 0.0f; + float v1 = 0.0f; + + for (uint32_t i = 0; i < height; i++) { + float stepY = yDivs[i]; + + float y2 = 0.0f; + if (i & 1) { + const float segment = stepY - previousStepY; + y2 = y1 + segment * stretchY; + } else { + y2 = y1 + stepY - previousStepY; + } + float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight; + + generateRow(vertex, y1, y2, v1, v2, xDivs, width, stretchX, + right - left, bitmapWidth, quadCount, colorKey); + + y1 = y2; + v1 = (stepY + 0.5f) / bitmapHeight; + + previousStepY = stepY; + } + + generateRow(vertex, y1, bottom - top, v1, 1.0f, xDivs, width, stretchX, + right - left, bitmapWidth, quadCount, colorKey); +} + +inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2, + const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth, + uint32_t& quadCount, const uint32_t colorKey) { + float previousStepX = 0.0f; + + float x1 = 0.0f; + float u1 = 0.0f; + + // Generate the row quad by quad + for (uint32_t i = 0; i < xCount; i++) { + float stepX = xDivs[i]; + + float x2 = 0.0f; + if (i & 1) { + const float segment = stepX - previousStepX; + x2 = x1 + segment * stretchX; + } else { + x2 = x1 + stepX - previousStepX; + } + float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth; + + generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount, colorKey); + + x1 = x2; + u1 = (stepX + 0.5f) / bitmapWidth; + + previousStepX = stepX; + } + + generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey); +} + +inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, + float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) { + if (((colorKey >> quadCount++) & 0x1) == 1) { + return; + } + + // Left triangle + TextureVertex::set(vertex++, x1, y1, u1, v1); + TextureVertex::set(vertex++, x2, y1, u2, v1); + TextureVertex::set(vertex++, x1, y2, u1, v2); + + // Right triangle + TextureVertex::set(vertex++, x1, y2, u1, v2); + TextureVertex::set(vertex++, x2, y1, u2, v1); + TextureVertex::set(vertex++, x2, y2, u2, v2); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h new file mode 100644 index 0000000..54c9d6c --- /dev/null +++ b/libs/hwui/Patch.h @@ -0,0 +1,112 @@ +/* + * 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_UI_PATCH_H +#define ANDROID_UI_PATCH_H + +#include <sys/types.h> + +#include "Vertex.h" +#include "utils/Compare.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// 9-patch structures +/////////////////////////////////////////////////////////////////////////////// + +/** + * Description of a patch. + */ +struct PatchDescription { + PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0), + xCount(0), yCount(0), emptyCount(0), colorKey(0) { } + PatchDescription(const float bitmapWidth, const float bitmapHeight, + const float pixelWidth, const float pixelHeight, + const uint32_t xCount, const uint32_t yCount, + const int8_t emptyCount, const uint32_t colorKey): + bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight), + pixelWidth(pixelWidth), pixelHeight(pixelHeight), + xCount(xCount), yCount(yCount), + emptyCount(emptyCount), colorKey(colorKey) { } + PatchDescription(const PatchDescription& description): + bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight), + pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight), + xCount(description.xCount), yCount(description.yCount), + emptyCount(description.emptyCount), colorKey(description.colorKey) { } + + float bitmapWidth; + float bitmapHeight; + float pixelWidth; + float pixelHeight; + uint32_t xCount; + uint32_t yCount; + int8_t emptyCount; + uint32_t colorKey; + + bool operator<(const PatchDescription& rhs) const { + compare(bitmapWidth) { + compare(bitmapHeight) { + compare(pixelWidth) { + compare(pixelHeight) { + compareI(xCount) { + compareI(yCount) { + compareI(emptyCount) { + compareI(colorKey) return false; + } + } + } + } + } + } + } + return false; + } +}; // struct PatchDescription + +/** + * An OpenGL patch. This contains an array of vertices and an array of + * indices to render the vertices. + */ +struct Patch { + Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads = 0); + ~Patch(); + + void updateVertices(const float bitmapWidth, const float bitmapHeight, + float left, float top, float right, float bottom, + const int32_t* xDivs, const int32_t* yDivs, + const uint32_t width, const uint32_t height, + const uint32_t colorKey = 0); + + TextureVertex* vertices; + uint32_t verticesCount; + +private: + static inline void generateRow(TextureVertex*& vertex, float y1, float y2, + float v1, float v2, const int32_t xDivs[], uint32_t xCount, + float stretchX, float width, float bitmapWidth, + uint32_t& quadCount, const uint32_t colorKey); + static inline void generateQuad(TextureVertex*& vertex, + float x1, float y1, float x2, float y2, + float u1, float v1, float u2, float v2, + uint32_t& quadCount, const uint32_t colorKey); +}; // struct Patch + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_PATCH_H diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp new file mode 100644 index 0000000..4762d21 --- /dev/null +++ b/libs/hwui/PatchCache.cpp @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <utils/Log.h> + +#include "PatchCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +PatchCache::PatchCache(): mMaxEntries(DEFAULT_PATCH_CACHE_SIZE) { +} + +PatchCache::PatchCache(uint32_t maxEntries): mMaxEntries(maxEntries) { +} + +PatchCache::~PatchCache() { + clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void PatchCache::clear() { + size_t count = mCache.size(); + for (size_t i = 0; i < count; i++) { + delete mCache.valueAt(i); + } + mCache.clear(); +} + +Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight, + const float pixelWidth, const float pixelHeight, + const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, + const uint32_t width, const uint32_t height, const int8_t numColors) { + + int8_t transparentQuads = 0; + uint32_t colorKey = 0; + + if (uint8_t(numColors) < sizeof(uint32_t) * 4) { + for (int8_t i = 0; i < numColors; i++) { + if (colors[i] == 0x0) { + transparentQuads++; + colorKey |= 0x1 << i; + } + } + } + + const PatchDescription description(bitmapWidth, bitmapHeight, + pixelWidth, pixelHeight, width, height, transparentQuads, colorKey); + + ssize_t index = mCache.indexOfKey(description); + Patch* mesh = NULL; + if (index >= 0) { + mesh = mCache.valueAt(index); + } + + if (!mesh) { + PATCH_LOGD("New patch mesh " + "xCount=%d yCount=%d, w=%.2f h=%.2f, bw=%.2f bh=%.2f", + width, height, pixelWidth, pixelHeight, bitmapWidth, bitmapHeight); + + mesh = new Patch(width, height, transparentQuads); + mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, + pixelWidth, pixelHeight, xDivs, yDivs, width, height, colorKey); + + if (mCache.size() >= mMaxEntries) { + delete mCache.valueAt(mCache.size() - 1); + mCache.removeItemsAt(mCache.size() - 1, 1); + } + + mCache.add(description, mesh); + } + + return mesh; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h new file mode 100644 index 0000000..f4eeb09 --- /dev/null +++ b/libs/hwui/PatchCache.h @@ -0,0 +1,65 @@ +/* + * 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_UI_PATCH_CACHE_H +#define ANDROID_UI_PATCH_CACHE_H + +#include <utils/KeyedVector.h> + +#include "Patch.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#define DEBUG_PATCHES 0 + +// Debug +#if DEBUG_PATCHES + #define PATCH_LOGD(...) LOGD(__VA_ARGS__) +#else + #define PATCH_LOGD(...) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Cache +/////////////////////////////////////////////////////////////////////////////// + +class PatchCache { +public: + PatchCache(); + PatchCache(uint32_t maxCapacity); + ~PatchCache(); + + Patch* get(const float bitmapWidth, const float bitmapHeight, + const float pixelWidth, const float pixelHeight, + const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, + const uint32_t width, const uint32_t height, const int8_t numColors); + void clear(); + +private: + uint32_t mMaxEntries; + KeyedVector<PatchDescription, Patch*> mCache; +}; // class PatchCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_PATCH_CACHE_H diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp new file mode 100644 index 0000000..377727b --- /dev/null +++ b/libs/hwui/PathCache.cpp @@ -0,0 +1,224 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <GLES2/gl2.h> + +#include <SkCanvas.h> +#include <SkRect.h> + +#include <utils/threads.h> + +#include "PathCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +PathCache::PathCache(): + mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting path cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); + } + init(); +} + +PathCache::PathCache(uint32_t maxByteSize): + mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(maxByteSize) { + init(); +} + +PathCache::~PathCache() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +void PathCache::init() { + mCache.setOnEntryRemovedListener(this); + + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + mMaxTextureSize = maxTextureSize; +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t PathCache::getSize() { + Mutex::Autolock _l(mLock); + return mSize; +} + +uint32_t PathCache::getMaxSize() { + Mutex::Autolock _l(mLock); + return mMaxSize; +} + +void PathCache::setMaxSize(uint32_t maxSize) { + Mutex::Autolock _l(mLock); + mMaxSize = maxSize; + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +/////////////////////////////////////////////////////////////////////////////// + +void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) { + const uint32_t size = texture->width * texture->height; + mSize -= size; + + if (texture) { + glDeleteTextures(1, &texture->id); + delete texture; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void PathCache::remove(SkPath* path) { + Mutex::Autolock _l(mLock); + // TODO: Linear search... + for (uint32_t i = 0; i < mCache.size(); i++) { + if (mCache.getKeyAt(i).path == path) { + mCache.removeAt(i); + } + } +} + +PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { + PathCacheEntry entry(path, paint); + + mLock.lock(); + PathTexture* texture = mCache.get(entry); + mLock.unlock(); + + if (!texture) { + texture = addTexture(entry, path, paint); + } else if (path->getGenerationID() != texture->generation) { + mLock.lock(); + mCache.remove(entry); + mLock.unlock(); + texture = addTexture(entry, path, paint); + } + + return texture; +} + +PathTexture* PathCache::addTexture(const PathCacheEntry& entry, + const SkPath *path, const SkPaint* paint) { + const SkRect& bounds = path->getBounds(); + + const float pathWidth = fmax(bounds.width(), 1.0f); + const float pathHeight = fmax(bounds.height(), 1.0f); + + if (pathWidth > mMaxTextureSize || pathHeight > mMaxTextureSize) { + LOGW("Path too large to be rendered into a texture"); + return NULL; + } + + const float offset = entry.strokeWidth * 1.5f; + const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5); + const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5); + + const uint32_t size = width * height; + // Don't even try to cache a bitmap that's bigger than the cache + if (size < mMaxSize) { + mLock.lock(); + while (mSize + size > mMaxSize) { + mCache.removeOldest(); + } + mLock.unlock(); + } + + PathTexture* texture = new PathTexture; + texture->left = bounds.fLeft; + texture->top = bounds.fTop; + texture->offset = offset; + texture->width = width; + texture->height = height; + texture->generation = path->getGenerationID(); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kA8_Config, width, height); + bitmap.allocPixels(); + bitmap.eraseColor(0); + + SkCanvas canvas(bitmap); + canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset); + canvas.drawPath(*path, *paint); + + generateTexture(bitmap, texture); + + if (size < mMaxSize) { + mLock.lock(); + mSize += size; + mCache.put(entry, texture); + mLock.unlock(); + } else { + texture->cleanup = true; + } + + return texture; +} + +void PathCache::clear() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) { + SkAutoLockPixels alp(bitmap); + if (!bitmap.readyToDraw()) { + LOGE("Cannot generate texture from bitmap"); + return; + } + + glGenTextures(1, &texture->id); + + glBindTexture(GL_TEXTURE_2D, texture->id); + // Textures are Alpha8 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + texture->blend = true; + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels()); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h new file mode 100644 index 0000000..0c74261 --- /dev/null +++ b/libs/hwui/PathCache.h @@ -0,0 +1,173 @@ +/* + * 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_UI_PATH_CACHE_H +#define ANDROID_UI_PATH_CACHE_H + +#include <SkBitmap.h> +#include <SkPaint.h> +#include <SkPath.h> + +#include "Texture.h" +#include "utils/Compare.h" +#include "utils/GenerationCache.h" + +namespace android { +namespace uirenderer { + +/** + * Describe a path in the path cache. + */ +struct PathCacheEntry { + PathCacheEntry() { + path = NULL; + join = SkPaint::kDefault_Join; + cap = SkPaint::kDefault_Cap; + style = SkPaint::kFill_Style; + miter = 4.0f; + strokeWidth = 1.0f; + } + + PathCacheEntry(const PathCacheEntry& entry): + path(entry.path), join(entry.join), cap(entry.cap), + style(entry.style), miter(entry.miter), + strokeWidth(entry.strokeWidth) { + } + + PathCacheEntry(SkPath* path, SkPaint* paint) { + this->path = path; + join = paint->getStrokeJoin(); + cap = paint->getStrokeCap(); + miter = paint->getStrokeMiter(); + strokeWidth = paint->getStrokeWidth(); + style = paint->getStyle(); + } + + SkPath* path; + SkPaint::Join join; + SkPaint::Cap cap; + SkPaint::Style style; + float miter; + float strokeWidth; + + bool operator<(const PathCacheEntry& rhs) const { + compareI(path) { + compareI(join) { + compareI(cap) { + compareI(style) { + compare(miter) { + compare(strokeWidth) return false; + } + } + } + } + } + return false; + } +}; // struct PathCacheEntry + +/** + * Alpha texture used to represent a path. + */ +struct PathTexture: public Texture { + PathTexture(): Texture() { + } + + /** + * Left coordinate of the path bounds. + */ + float left; + /** + * Top coordinate of the path bounds. + */ + float top; + /** + * Offset to draw the path at the correct origin. + */ + float offset; +}; // struct PathTexture + +/** + * A simple LRU path cache. The cache has a maximum size expressed in bytes. + * Any texture added to the cache causing the cache to grow beyond the maximum + * allowed size will also cause the oldest texture to be kicked out. + */ +class PathCache: public OnEntryRemoved<PathCacheEntry, PathTexture*> { +public: + PathCache(); + PathCache(uint32_t maxByteSize); + ~PathCache(); + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(PathCacheEntry& path, PathTexture*& texture); + + /** + * Returns the texture associated with the specified path. If the texture + * cannot be found in the cache, a new texture is generated. + */ + PathTexture* get(SkPath* path, SkPaint* paint); + /** + * Clears the cache. This causes all textures to be deleted. + */ + void clear(); + /** + * Removes an entry. + */ + void remove(SkPath* path); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + /** + * Generates the texture from a bitmap into the specified texture structure. + */ + void generateTexture(SkBitmap& bitmap, Texture* texture); + + PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint); + + void init(); + + GenerationCache<PathCacheEntry, PathTexture*> mCache; + + uint32_t mSize; + uint32_t mMaxSize; + GLuint mMaxTextureSize; + + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ + mutable Mutex mLock; +}; // class PathCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_PATH_CACHE_H diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp new file mode 100644 index 0000000..25674c6 --- /dev/null +++ b/libs/hwui/Program.cpp @@ -0,0 +1,144 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include "Program.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Shaders +/////////////////////////////////////////////////////////////////////////////// + +#define SHADER_SOURCE(name, source) const char* name = #source + +/////////////////////////////////////////////////////////////////////////////// +// Base program +/////////////////////////////////////////////////////////////////////////////// + +Program::Program(const char* vertex, const char* fragment) { + vertexShader = buildShader(vertex, GL_VERTEX_SHADER); + fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); + + id = glCreateProgram(); + glAttachShader(id, vertexShader); + glAttachShader(id, fragmentShader); + glLinkProgram(id); + + GLint status; + glGetProgramiv(id, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + GLint infoLen = 0; + glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) { + GLchar log[infoLen]; + glGetProgramInfoLog(id, infoLen, 0, &log[0]); + LOGE("Error while linking shaders: %s", log); + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + glDeleteProgram(id); + } + + mUse = false; + + position = addAttrib("position"); + transform = addUniform("transform"); +} + +Program::~Program() { + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + glDeleteProgram(id); +} + +int Program::addAttrib(const char* name) { + int slot = glGetAttribLocation(id, name); + attributes.add(name, slot); + return slot; +} + +int Program::getAttrib(const char* name) { + ssize_t index = attributes.indexOfKey(name); + if (index >= 0) { + return attributes.valueAt(index); + } + return addAttrib(name); +} + +int Program::addUniform(const char* name) { + int slot = glGetUniformLocation(id, name); + uniforms.add(name, slot); + return slot; +} + +int Program::getUniform(const char* name) { + ssize_t index = uniforms.indexOfKey(name); + if (index >= 0) { + return uniforms.valueAt(index); + } + return addUniform(name); +} + +GLuint Program::buildShader(const char* source, GLenum type) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + // Some drivers return wrong values for GL_INFO_LOG_LENGTH + // use a fixed size instead + GLchar log[512]; + glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); + LOGE("Error while compiling shader: %s", log); + glDeleteShader(shader); + } + + return shader; +} + +void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, + const mat4& transformMatrix) { + mat4 t(projectionMatrix); + t.multiply(transformMatrix); + t.multiply(modelViewMatrix); + + glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); +} + +void Program::setColor(const float r, const float g, const float b, const float a) { + glUniform4f(getUniform("color"), r, g, b, a); +} + +void Program::use() { + glUseProgram(id); + mUse = true; + + glEnableVertexAttribArray(position); +} + +void Program::remove() { + mUse = false; + + glDisableVertexAttribArray(position); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h new file mode 100644 index 0000000..026097c --- /dev/null +++ b/libs/hwui/Program.h @@ -0,0 +1,134 @@ +/* + * 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_UI_PROGRAM_H +#define ANDROID_UI_PROGRAM_H + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <utils/KeyedVector.h> + +#include "Matrix.h" + +namespace android { +namespace uirenderer { + +/** + * A program holds a vertex and a fragment shader. It offers several utility + * methods to query attributes and uniforms. + */ +class Program { +public: + /** + * Creates a new program with the specified vertex and fragment + * shaders sources. + */ + Program(const char* vertex, const char* fragment); + virtual ~Program(); + + /** + * Binds this program to the GL context. + */ + virtual void use(); + + /** + * Marks this program as unused. This will not unbind + * the program from the GL context. + */ + virtual void remove(); + + /** + * Returns the OpenGL name of the specified attribute. + */ + int getAttrib(const char* name); + + /** + * Returns the OpenGL name of the specified uniform. + */ + int getUniform(const char* name); + + /** + * Indicates whether this program is currently in use with + * the GL context. + */ + inline bool isInUse() const { + return mUse; + } + + /** + * Binds the program with the specified projection, modelView and + * transform matrices. + */ + void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, + const mat4& transformMatrix); + + /** + * Sets the color associated with this shader. + */ + void setColor(const float r, const float g, const float b, const float a); + + /** + * Name of the position attribute. + */ + int position; + + /** + * Name of the transform uniform. + */ + int transform; + +protected: + /** + * Adds an attribute with the specified name. + * + * @return The OpenGL name of the attribute. + */ + int addAttrib(const char* name); + + /** + * Adds a uniform with the specified name. + * + * @return The OpenGL name of the uniform. + */ + int addUniform(const char* name); + +private: + /** + * Compiles the specified shader of the specified type. + * + * @return The name of the compiled shader. + */ + GLuint buildShader(const char* source, GLenum type); + + // Name of the OpenGL program + GLuint id; + + // Name of the shaders + GLuint vertexShader; + GLuint fragmentShader; + + // Keeps track of attributes and uniforms slots + KeyedVector<const char*, int> attributes; + KeyedVector<const char*, int> uniforms; + + bool mUse; +}; // class Program + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_PROGRAM_H diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp new file mode 100644 index 0000000..3cd85c8 --- /dev/null +++ b/libs/hwui/ProgramCache.cpp @@ -0,0 +1,615 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <utils/String8.h> + +#include "ProgramCache.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +#define MODULATE_OP_NO_MODULATE 0 +#define MODULATE_OP_MODULATE 1 +#define MODULATE_OP_MODULATE_A8 2 + +/////////////////////////////////////////////////////////////////////////////// +// Vertex shaders snippets +/////////////////////////////////////////////////////////////////////////////// + +const char* gVS_Header_Attributes = + "attribute vec4 position;\n"; +const char* gVS_Header_Attributes_TexCoords = + "attribute vec2 texCoords;\n"; +const char* gVS_Header_Uniforms = + "uniform mat4 transform;\n"; +const char* gVS_Header_Uniforms_HasGradient[3] = { + // Linear + "uniform mat4 screenSpace;\n", + // Circular + "uniform mat4 screenSpace;\n", + // Sweep + "uniform mat4 screenSpace;\n" +}; +const char* gVS_Header_Uniforms_HasBitmap = + "uniform mat4 textureTransform;\n" + "uniform vec2 textureDimension;\n"; +const char* gVS_Header_Varyings_HasTexture = + "varying vec2 outTexCoords;\n"; +const char* gVS_Header_Varyings_HasBitmap = + "varying vec2 outBitmapTexCoords;\n"; +const char* gVS_Header_Varyings_HasGradient[3] = { + // Linear + "varying vec2 linear;\n", + // Circular + "varying vec2 circular;\n", + // Sweep + "varying vec2 sweep;\n" +}; +const char* gVS_Main = + "\nvoid main(void) {\n"; +const char* gVS_Main_OutTexCoords = + " outTexCoords = texCoords;\n"; +const char* gVS_Main_OutGradient[3] = { + // Linear + " linear = vec2((screenSpace * position).x, 0.5);\n", + // Circular + " circular = (screenSpace * position).xy;\n", + // Sweep + " sweep = (screenSpace * position).xy;\n" +}; +const char* gVS_Main_OutBitmapTexCoords = + " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; +const char* gVS_Main_Position = + " gl_Position = transform * position;\n"; +const char* gVS_Footer = + "}\n\n"; + +/////////////////////////////////////////////////////////////////////////////// +// Fragment shaders snippets +/////////////////////////////////////////////////////////////////////////////// + +const char* gFS_Header_Extension_FramebufferFetch = + "#extension GL_NV_shader_framebuffer_fetch : enable\n\n"; +const char* gFS_Header = + "precision mediump float;\n\n"; +const char* gFS_Uniforms_Color = + "uniform vec4 color;\n"; +const char* gFS_Uniforms_TextureSampler = + "uniform sampler2D sampler;\n"; +const char* gFS_Uniforms_GradientSampler[3] = { + // Linear + "uniform sampler2D gradientSampler;\n", + // Circular + "uniform sampler2D gradientSampler;\n", + // Sweep + "uniform sampler2D gradientSampler;\n" +}; +const char* gFS_Uniforms_BitmapSampler = + "uniform sampler2D bitmapSampler;\n"; +const char* gFS_Uniforms_ColorOp[4] = { + // None + "", + // Matrix + "uniform mat4 colorMatrix;\n" + "uniform vec4 colorMatrixVector;\n", + // Lighting + "uniform vec4 lightingMul;\n" + "uniform vec4 lightingAdd;\n", + // PorterDuff + "uniform vec4 colorBlend;\n" +}; +const char* gFS_Main = + "\nvoid main(void) {\n" + " lowp vec4 fragColor;\n"; + +// Fast cases +const char* gFS_Fast_SingleColor = + "\nvoid main(void) {\n" + " gl_FragColor = color;\n" + "}\n\n"; +const char* gFS_Fast_SingleTexture = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateTexture = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(sampler, outTexCoords);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateA8Texture = + "\nvoid main(void) {\n" + " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n" + "}\n\n"; +const char* gFS_Fast_SingleGradient = + "\nvoid main(void) {\n" + " gl_FragColor = texture2D(gradientSampler, linear);\n" + "}\n\n"; +const char* gFS_Fast_SingleModulateGradient = + "\nvoid main(void) {\n" + " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n" + "}\n\n"; + +// General case +const char* gFS_Main_FetchColor = + " fragColor = color;\n"; +const char* gFS_Main_FetchTexture[2] = { + // Don't modulate + " fragColor = texture2D(sampler, outTexCoords);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords);\n" +}; +const char* gFS_Main_FetchA8Texture[2] = { + // Don't modulate + " fragColor = texture2D(sampler, outTexCoords);\n", + // Modulate + " fragColor = color * texture2D(sampler, outTexCoords).a;\n" +}; +const char* gFS_Main_FetchGradient[3] = { + // Linear + " vec4 gradientColor = texture2D(gradientSampler, linear);\n", + // Circular + " float index = length(circular);\n" + " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", + // Sweep + " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" + " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n" +}; +const char* gFS_Main_FetchBitmap = + " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n"; +const char* gFS_Main_FetchBitmapNpot = + " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n"; +const char* gFS_Main_BlendShadersBG = + " fragColor = blendShaders(gradientColor, bitmapColor)"; +const char* gFS_Main_BlendShadersGB = + " fragColor = blendShaders(bitmapColor, gradientColor)"; +const char* gFS_Main_BlendShaders_Modulate[3] = { + // Don't modulate + ";\n", + // Modulate + " * fragColor.a;\n", + // Modulate with alpha 8 texture + " * texture2D(sampler, outTexCoords).a;\n" +}; +const char* gFS_Main_GradientShader_Modulate[3] = { + // Don't modulate + " fragColor = gradientColor;\n", + // Modulate + " fragColor = gradientColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n" + }; +const char* gFS_Main_BitmapShader_Modulate[3] = { + // Don't modulate + " fragColor = bitmapColor;\n", + // Modulate + " fragColor = bitmapColor * fragColor.a;\n", + // Modulate with alpha 8 texture + " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n" + }; +const char* gFS_Main_FragColor = + " gl_FragColor = fragColor;\n"; +const char* gFS_Main_FragColor_Blend = + " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n"; +const char* gFS_Main_FragColor_Blend_Swap = + " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n"; +const char* gFS_Main_ApplyColorOp[4] = { + // None + "", + // Matrix + // TODO: Fix premultiplied alpha computations for color matrix + " fragColor *= colorMatrix;\n" + " fragColor += colorMatrixVector;\n" + " fragColor.rgb *= fragColor.a;\n", + // Lighting + " float lightingAlpha = fragColor.a;\n" + " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n" + " fragColor.a = lightingAlpha;\n", + // PorterDuff + " fragColor = blendColors(colorBlend, fragColor);\n" +}; +const char* gFS_Footer = + "}\n\n"; + +/////////////////////////////////////////////////////////////////////////////// +// PorterDuff snippets +/////////////////////////////////////////////////////////////////////////////// + +const char* gBlendOps[18] = { + // Clear + "return vec4(0.0, 0.0, 0.0, 0.0);\n", + // Src + "return src;\n", + // Dst + "return dst;\n", + // SrcOver + "return src + dst * (1.0 - src.a);\n", + // DstOver + "return dst + src * (1.0 - dst.a);\n", + // SrcIn + "return src * dst.a;\n", + // DstIn + "return dst * src.a;\n", + // SrcOut + "return src * (1.0 - dst.a);\n", + // DstOut + "return dst * (1.0 - src.a);\n", + // SrcAtop + "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n", + // DstAtop + "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n", + // Xor + "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, " + "src.a + dst.a - 2.0 * src.a * dst.a);\n", + // Add + "return min(src + dst, 1.0);\n", + // Multiply + "return src * dst;\n", + // Screen + "return src + dst - src * dst;\n", + // Overlay + "return clamp(vec4(mix(" + "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), " + "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), " + "step(dst.a, 2.0 * dst.rgb)), " + "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n", + // Darken + "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " + "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", + // Lighten + "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " + "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", +}; + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructors +/////////////////////////////////////////////////////////////////////////////// + +ProgramCache::ProgramCache() { +} + +ProgramCache::~ProgramCache() { + clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Cache management +/////////////////////////////////////////////////////////////////////////////// + +void ProgramCache::clear() { + size_t count = mCache.size(); + for (size_t i = 0; i < count; i++) { + delete mCache.valueAt(i); + } + mCache.clear(); +} + +Program* ProgramCache::get(const ProgramDescription& description) { + programid key = description.key(); + ssize_t index = mCache.indexOfKey(key); + Program* program = NULL; + if (index < 0) { + description.log("Could not find program"); + program = generateProgram(description, key); + mCache.add(key, program); + } else { + program = mCache.valueAt(index); + } + return program; +} + +/////////////////////////////////////////////////////////////////////////////// +// Program generation +/////////////////////////////////////////////////////////////////////////////// + +Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) { + String8 vertexShader = generateVertexShader(description); + String8 fragmentShader = generateFragmentShader(description); + + Program* program = new Program(vertexShader.string(), fragmentShader.string()); + return program; +} + +String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { + // Add attributes + String8 shader(gVS_Header_Attributes); + if (description.hasTexture) { + shader.append(gVS_Header_Attributes_TexCoords); + } + // Uniforms + shader.append(gVS_Header_Uniforms); + if (description.hasGradient) { + shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]); + } + if (description.hasBitmap) { + shader.append(gVS_Header_Uniforms_HasBitmap); + } + // Varyings + if (description.hasTexture) { + shader.append(gVS_Header_Varyings_HasTexture); + } + if (description.hasGradient) { + shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); + } + if (description.hasBitmap) { + shader.append(gVS_Header_Varyings_HasBitmap); + } + + // Begin the shader + shader.append(gVS_Main); { + if (description.hasTexture) { + shader.append(gVS_Main_OutTexCoords); + } + if (description.hasGradient) { + shader.append(gVS_Main_OutGradient[description.gradientType]); + } + if (description.hasBitmap) { + shader.append(gVS_Main_OutBitmapTexCoords); + } + // Output transformed position + shader.append(gVS_Main_Position); + } + // End the shader + shader.append(gVS_Footer); + + PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); + + return shader; +} + +String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { + // Set the default precision + String8 shader; + + const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; + if (blendFramebuffer) { + shader.append(gFS_Header_Extension_FramebufferFetch); + } + + shader.append(gFS_Header); + + // Varyings + if (description.hasTexture) { + shader.append(gVS_Header_Varyings_HasTexture); + } + if (description.hasGradient) { + shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); + } + if (description.hasBitmap) { + shader.append(gVS_Header_Varyings_HasBitmap); + } + + // Uniforms + int modulateOp = MODULATE_OP_NO_MODULATE; + const bool singleColor = !description.hasTexture && + !description.hasGradient && !description.hasBitmap; + + if (description.modulate || singleColor) { + shader.append(gFS_Uniforms_Color); + if (!singleColor) modulateOp = MODULATE_OP_MODULATE; + } + if (description.hasTexture) { + shader.append(gFS_Uniforms_TextureSampler); + } + if (description.hasGradient) { + shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); + } + + // Optimization for common cases + if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) { + bool fast = false; + + const bool noShader = !description.hasGradient && !description.hasBitmap; + const bool singleTexture = description.hasTexture && + !description.hasAlpha8Texture && noShader; + const bool singleA8Texture = description.hasTexture && + description.hasAlpha8Texture && noShader; + const bool singleGradient = !description.hasTexture && + description.hasGradient && !description.hasBitmap && + description.gradientType == ProgramDescription::kGradientLinear; + + if (singleColor) { + shader.append(gFS_Fast_SingleColor); + fast = true; + } else if (singleTexture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleTexture); + } else { + shader.append(gFS_Fast_SingleModulateTexture); + } + fast = true; + } else if (singleA8Texture) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleA8Texture); + } else { + shader.append(gFS_Fast_SingleModulateA8Texture); + } + fast = true; + } else if (singleGradient) { + if (!description.modulate) { + shader.append(gFS_Fast_SingleGradient); + } else { + shader.append(gFS_Fast_SingleModulateGradient); + } + fast = true; + } + + if (fast) { + if (DEBUG_PROGRAM_CACHE) { + PROGRAM_LOGD("*** Fast case:\n"); + PROGRAM_LOGD("*** Generated fragment shader:\n\n"); + printLongString(shader); + } + + return shader; + } + } + + if (description.hasBitmap) { + shader.append(gFS_Uniforms_BitmapSampler); + } + shader.append(gFS_Uniforms_ColorOp[description.colorOp]); + + // Generate required functions + if (description.hasGradient && description.hasBitmap) { + generateBlend(shader, "blendShaders", description.shadersMode); + } + if (description.colorOp == ProgramDescription::kColorBlend) { + generateBlend(shader, "blendColors", description.colorMode); + } + if (blendFramebuffer) { + generateBlend(shader, "blendFramebuffer", description.framebufferMode); + } + if (description.isBitmapNpot) { + generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); + } + + // Begin the shader + shader.append(gFS_Main); { + // Stores the result in fragColor directly + if (description.hasTexture) { + if (description.hasAlpha8Texture) { + if (!description.hasGradient && !description.hasBitmap) { + shader.append(gFS_Main_FetchA8Texture[modulateOp]); + } + } else { + shader.append(gFS_Main_FetchTexture[modulateOp]); + } + } else { + if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { + shader.append(gFS_Main_FetchColor); + } + } + if (description.hasGradient) { + shader.append(gFS_Main_FetchGradient[description.gradientType]); + } + if (description.hasBitmap) { + if (!description.isBitmapNpot) { + shader.append(gFS_Main_FetchBitmap); + } else { + shader.append(gFS_Main_FetchBitmapNpot); + } + } + // Case when we have two shaders set + if (description.hasGradient && description.hasBitmap) { + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + if (description.isBitmapFirst) { + shader.append(gFS_Main_BlendShadersBG); + } else { + shader.append(gFS_Main_BlendShadersGB); + } + shader.append(gFS_Main_BlendShaders_Modulate[op]); + } else { + if (description.hasGradient) { + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_GradientShader_Modulate[op]); + } else if (description.hasBitmap) { + int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; + shader.append(gFS_Main_BitmapShader_Modulate[op]); + } + } + // Apply the color op if needed + shader.append(gFS_Main_ApplyColorOp[description.colorOp]); + // Output the fragment + if (!blendFramebuffer) { + shader.append(gFS_Main_FragColor); + } else { + shader.append(!description.swapSrcDst ? + gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); + } + } + // End the shader + shader.append(gFS_Footer); + + if (DEBUG_PROGRAM_CACHE) { + PROGRAM_LOGD("*** Generated fragment shader:\n\n"); + printLongString(shader); + } + + return shader; +} + +void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) { + shader.append("\nvec4 "); + shader.append(name); + shader.append("(vec4 src, vec4 dst) {\n"); + shader.append(" "); + shader.append(gBlendOps[mode]); + shader.append("}\n"); +} + +void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { + shader.append("\nvec2 wrap(vec2 texCoords) {\n"); + if (wrapS == GL_MIRRORED_REPEAT) { + shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n"); + shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); + } + if (wrapT == GL_MIRRORED_REPEAT) { + shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n"); + shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); + } + shader.append(" return vec2("); + switch (wrapS) { + case GL_CLAMP_TO_EDGE: + shader.append("texCoords.x"); + break; + case GL_REPEAT: + shader.append("mod(texCoords.x, 1.0)"); + break; + case GL_MIRRORED_REPEAT: + shader.append("xMod2"); + break; + } + shader.append(", "); + switch (wrapT) { + case GL_CLAMP_TO_EDGE: + shader.append("texCoords.y"); + break; + case GL_REPEAT: + shader.append("mod(texCoords.y, 1.0)"); + break; + case GL_MIRRORED_REPEAT: + shader.append("yMod2"); + break; + } + shader.append(");\n"); + shader.append("}\n"); +} + +void ProgramCache::printLongString(const String8& shader) const { + ssize_t index = 0; + ssize_t lastIndex = 0; + const char* str = shader.string(); + while ((index = shader.find("\n", index)) > -1) { + String8 line(str, index - lastIndex); + if (line.length() == 0) line.append("\n"); + PROGRAM_LOGD("%s", line.string()); + index++; + str += (index - lastIndex); + lastIndex = index; + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h new file mode 100644 index 0000000..9cb13b3 --- /dev/null +++ b/libs/hwui/ProgramCache.h @@ -0,0 +1,261 @@ +/* + * 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_UI_PROGRAM_CACHE_H +#define ANDROID_UI_PROGRAM_CACHE_H + +#include <utils/KeyedVector.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#include <GLES2/gl2.h> + +#include <SkXfermode.h> + +#include "Program.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#define DEBUG_PROGRAM_CACHE 0 + +// Debug +#if DEBUG_PROGRAM_CACHE + #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__) +#else + #define PROGRAM_LOGD(...) +#endif + +// TODO: This should be set in properties +#define PANEL_BIT_DEPTH 20 +#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH)) +#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH) + +#define PROGRAM_KEY_TEXTURE 0x1 +#define PROGRAM_KEY_A8_TEXTURE 0x2 +#define PROGRAM_KEY_BITMAP 0x4 +#define PROGRAM_KEY_GRADIENT 0x8 +#define PROGRAM_KEY_BITMAP_FIRST 0x10 +#define PROGRAM_KEY_COLOR_MATRIX 0x20 +#define PROGRAM_KEY_COLOR_LIGHTING 0x40 +#define PROGRAM_KEY_COLOR_BLEND 0x80 +#define PROGRAM_KEY_BITMAP_NPOT 0x100 +#define PROGRAM_KEY_SWAP_SRC_DST 0x2000 + +#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 +#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800 + +// Encode the xfermodes on 6 bits +#define PROGRAM_MAX_XFERMODE 0x1f +#define PROGRAM_XFERMODE_SHADER_SHIFT 26 +#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20 +#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14 + +#define PROGRAM_BITMAP_WRAPS_SHIFT 9 +#define PROGRAM_BITMAP_WRAPT_SHIFT 11 + +#define PROGRAM_GRADIENT_TYPE_SHIFT 33 +#define PROGRAM_MODULATE 35 + +/////////////////////////////////////////////////////////////////////////////// +// Types +/////////////////////////////////////////////////////////////////////////////// + +typedef uint64_t programid; + +/////////////////////////////////////////////////////////////////////////////// +// Cache +/////////////////////////////////////////////////////////////////////////////// + +/** + * Describe the features required for a given program. The features + * determine the generation of both the vertex and fragment shaders. + * A ProgramDescription must be used in conjunction with a ProgramCache. + */ +struct ProgramDescription { + enum ColorModifier { + kColorNone, + kColorMatrix, + kColorLighting, + kColorBlend + }; + + enum Gradient { + kGradientLinear, + kGradientCircular, + kGradientSweep + }; + + ProgramDescription(): + hasTexture(false), hasAlpha8Texture(false), modulate(false), + hasBitmap(false), isBitmapNpot(false), hasGradient(false), + gradientType(kGradientLinear), + shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false), + bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE), + colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode), + framebufferMode(SkXfermode::kClear_Mode), swapSrcDst(false) { + } + + // Texturing + bool hasTexture; + bool hasAlpha8Texture; + + // Modulate, this should only be set when setColor() return true + bool modulate; + + // Shaders + bool hasBitmap; + bool isBitmapNpot; + + bool hasGradient; + Gradient gradientType; + + SkXfermode::Mode shadersMode; + + bool isBitmapFirst; + GLenum bitmapWrapS; + GLenum bitmapWrapT; + + // Color operations + ColorModifier colorOp; + SkXfermode::Mode colorMode; + + // Framebuffer blending (requires Extensions.hasFramebufferFetch()) + // Ignored for all values < SkXfermode::kPlus_Mode + SkXfermode::Mode framebufferMode; + bool swapSrcDst; + + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setColor(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD || + g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD; + return modulate; + } + + /** + * Indicates, for a given color, whether color modulation is required in + * the fragment shader. When this method returns true, the program should + * be provided with a modulation color. + */ + bool setAlpha8Color(const float r, const float g, const float b, const float a) { + modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD || + g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD; + return modulate; + } + + /** + * Computes the unique key identifying this program. + */ + programid key() const { + programid key = 0; + if (hasTexture) key |= PROGRAM_KEY_TEXTURE; + if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE; + if (hasBitmap) { + key |= PROGRAM_KEY_BITMAP; + if (isBitmapNpot) { + key |= PROGRAM_KEY_BITMAP_NPOT; + key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT; + key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT; + } + } + if (hasGradient) key |= PROGRAM_KEY_GRADIENT; + key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT; + if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST; + if (hasBitmap && hasGradient) { + key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT; + } + switch (colorOp) { + case kColorMatrix: + key |= PROGRAM_KEY_COLOR_MATRIX; + break; + case kColorLighting: + key |= PROGRAM_KEY_COLOR_LIGHTING; + break; + case kColorBlend: + key |= PROGRAM_KEY_COLOR_BLEND; + key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT; + break; + case kColorNone: + break; + } + key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT; + if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; + if (modulate) key |= programid(0x1) << PROGRAM_MODULATE; + return key; + } + + /** + * Logs the specified message followed by the key identifying this program. + */ + void log(const char* message) const { + programid k = key(); + PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), + uint32_t(k & 0xffffffff)); + } + +private: + inline uint32_t getEnumForWrap(GLenum wrap) const { + switch (wrap) { + case GL_CLAMP_TO_EDGE: + return 0; + case GL_REPEAT: + return 1; + case GL_MIRRORED_REPEAT: + return 2; + } + return 0; + } + +}; // struct ProgramDescription + +/** + * Generates and caches program. Programs are generated based on + * ProgramDescriptions. + */ +class ProgramCache { +public: + ProgramCache(); + ~ProgramCache(); + + Program* get(const ProgramDescription& description); + + void clear(); + +private: + Program* generateProgram(const ProgramDescription& description, programid key); + String8 generateVertexShader(const ProgramDescription& description); + String8 generateFragmentShader(const ProgramDescription& description); + void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode); + void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT); + + void printLongString(const String8& shader) const; + + KeyedVector<programid, Program*> mCache; +}; // class ProgramCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_PROGRAM_CACHE_H diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h new file mode 100644 index 0000000..db3cb4d --- /dev/null +++ b/libs/hwui/Properties.h @@ -0,0 +1,59 @@ +/* + * 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_UI_PROPERTIES_H +#define ANDROID_UI_PROPERTIES_H + +#include <cutils/properties.h> + +/** + * This file contains the list of system properties used to configure + * the OpenGLRenderer. + */ + +// These properties are defined in mega-bytes +#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size" +#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size" +#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size" +#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size" +#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size" +#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size" + +// These properties are defined in pixels +#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width" +#define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height" + +// Gamma (>= 1.0, <= 10.0) +#define PROPERTY_TEXT_GAMMA "ro.text_gamma" +#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold" +#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold" + +// Converts a number of mega-bytes into bytes +#define MB(s) s * 1024 * 1024 + +#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f +#define DEFAULT_LAYER_CACHE_SIZE 6.0f +#define DEFAULT_PATH_CACHE_SIZE 4.0f +#define DEFAULT_PATCH_CACHE_SIZE 512 +#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f +#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f +#define DEFAULT_FBO_CACHE_SIZE 25 + +#define DEFAULT_TEXT_GAMMA 1.4f +#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64 +#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192 + +#endif // ANDROID_UI_PROPERTIES_H diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h new file mode 100644 index 0000000..c571ea1 --- /dev/null +++ b/libs/hwui/Rect.h @@ -0,0 +1,167 @@ +/* + * 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_UI_RECT_H +#define ANDROID_UI_RECT_H + +#include <utils/Log.h> + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Structs +/////////////////////////////////////////////////////////////////////////////// + +struct Rect { + float left; + float top; + float right; + float bottom; + + Rect(): + left(0), + top(0), + right(0), + bottom(0) { + } + + Rect(float left, float top, float right, float bottom): + left(left), + top(top), + right(right), + bottom(bottom) { + } + + Rect(const Rect& r) { + set(r); + } + + Rect(Rect& r) { + set(r); + } + + Rect& operator=(const Rect& r) { + set(r); + return *this; + } + + Rect& operator=(Rect& r) { + set(r); + return *this; + } + + friend int operator==(const Rect& a, const Rect& b) { + return !memcmp(&a, &b, sizeof(a)); + } + + friend int operator!=(const Rect& a, const Rect& b) { + return memcmp(&a, &b, sizeof(a)); + } + + bool isEmpty() const { + return left >= right || top >= bottom; + } + + void setEmpty() { + memset(this, 0, sizeof(*this)); + } + + void set(float left, float top, float right, float bottom) { + this->left = left; + this->right = right; + this->top = top; + this->bottom = bottom; + } + + void set(const Rect& r) { + set(r.left, r.top, r.right, r.bottom); + } + + inline float getWidth() const { + return right - left; + } + + inline float getHeight() const { + return bottom - top; + } + + bool intersects(float left, float top, float right, float bottom) const { + return left < right && top < bottom && + this->left < this->right && this->top < this->bottom && + this->left < right && left < this->right && + this->top < bottom && top < this->bottom; + } + + bool intersects(const Rect& r) const { + return intersects(r.left, r.top, r.right, r.bottom); + } + + bool intersect(float left, float top, float right, float bottom) { + if (left < right && top < bottom && !this->isEmpty() && + this->left < right && left < this->right && + this->top < bottom && top < this->bottom) { + + if (this->left < left) this->left = left; + if (this->top < top) this->top = top; + if (this->right > right) this->right = right; + if (this->bottom > bottom) this->bottom = bottom; + + return true; + } + return false; + } + + bool intersect(const Rect& r) { + return intersect(r.left, r.top, r.right, r.bottom); + } + + bool unionWith(const Rect& r) { + if (r.left < r.right && r.top < r.bottom) { + if (left < right && top < bottom) { + if (left > r.left) left = r.left; + if (top > r.top) top = r.top; + if (right < r.right) right = r.right; + if (bottom < r.bottom) bottom = r.bottom; + return true; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + return true; + } + } + return false; + } + + void snapToPixelBoundaries() { + left = floorf(left); + top = floorf(top); + right = ceilf(right); + bottom = ceilf(bottom); + } + + void dump() const { + LOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom); + } + +}; // struct Rect + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_RECT_H diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp new file mode 100644 index 0000000..fe57ae7 --- /dev/null +++ b/libs/hwui/SkiaColorFilter.cpp @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#include "SkiaColorFilter.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Base color filter +/////////////////////////////////////////////////////////////////////////////// + +SkiaColorFilter::SkiaColorFilter(Type type, bool blend): mType(type), mBlend(blend) { +} + +SkiaColorFilter::~SkiaColorFilter() { +} + +/////////////////////////////////////////////////////////////////////////////// +// Color matrix filter +/////////////////////////////////////////////////////////////////////////////// + +SkiaColorMatrixFilter::SkiaColorMatrixFilter(float* matrix, float* vector): + SkiaColorFilter(kColorMatrix, true), mMatrix(matrix), mVector(vector) { +} + +SkiaColorMatrixFilter::~SkiaColorMatrixFilter() { + delete[] mMatrix; + delete[] mVector; +} + +void SkiaColorMatrixFilter::describe(ProgramDescription& description, + const Extensions& extensions) { + description.colorOp = ProgramDescription::kColorMatrix; +} + +void SkiaColorMatrixFilter::setupProgram(Program* program) { + glUniformMatrix4fv(program->getUniform("colorMatrix"), 1, GL_FALSE, &mMatrix[0]); + glUniform4fv(program->getUniform("colorMatrixVector"), 1, mVector); +} + +/////////////////////////////////////////////////////////////////////////////// +// Lighting color filter +/////////////////////////////////////////////////////////////////////////////// + +SkiaLightingFilter::SkiaLightingFilter(int multiply, int add): + SkiaColorFilter(kLighting, true) { + mMulR = ((multiply >> 16) & 0xFF) / 255.0f; + mMulG = ((multiply >> 8) & 0xFF) / 255.0f; + mMulB = ((multiply ) & 0xFF) / 255.0f; + + mAddR = ((add >> 16) & 0xFF) / 255.0f; + mAddG = ((add >> 8) & 0xFF) / 255.0f; + mAddB = ((add ) & 0xFF) / 255.0f; +} + +void SkiaLightingFilter::describe(ProgramDescription& description, const Extensions& extensions) { + description.colorOp = ProgramDescription::kColorLighting; +} + +void SkiaLightingFilter::setupProgram(Program* program) { + glUniform4f(program->getUniform("lightingMul"), mMulR, mMulG, mMulB, 1.0f); + glUniform4f(program->getUniform("lightingAdd"), mAddR, mAddG, mAddB, 0.0f); +} + +/////////////////////////////////////////////////////////////////////////////// +// Blend color filter +/////////////////////////////////////////////////////////////////////////////// + +SkiaBlendFilter::SkiaBlendFilter(int color, SkXfermode::Mode mode): + SkiaColorFilter(kBlend, true), mMode(mode) { + const int alpha = (color >> 24) & 0xFF; + mA = alpha / 255.0f; + mR = mA * ((color >> 16) & 0xFF) / 255.0f; + mG = mA * ((color >> 8) & 0xFF) / 255.0f; + mB = mA * ((color ) & 0xFF) / 255.0f; +} + +void SkiaBlendFilter::describe(ProgramDescription& description, const Extensions& extensions) { + description.colorOp = ProgramDescription::kColorBlend; + description.colorMode = mMode; +} + +void SkiaBlendFilter::setupProgram(Program* program) { + glUniform4f(program->getUniform("colorBlend"), mR, mG, mB, mA); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h new file mode 100644 index 0000000..865b6f0 --- /dev/null +++ b/libs/hwui/SkiaColorFilter.h @@ -0,0 +1,118 @@ +/* + * 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_UI_SKIA_COLOR_FILTER_H +#define ANDROID_UI_SKIA_COLOR_FILTER_H + +#include <GLES2/gl2.h> + +#include "ProgramCache.h" +#include "Extensions.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Base color filter +/////////////////////////////////////////////////////////////////////////////// + +/** + * Represents a Skia color filter. A color filter modifies a ProgramDescription + * and sets uniforms on the resulting shaders. + */ +struct SkiaColorFilter { + /** + * Type of Skia color filter in use. + */ + enum Type { + kNone, + kColorMatrix, + kLighting, + kBlend, + }; + + SkiaColorFilter(Type type, bool blend); + virtual ~SkiaColorFilter(); + + virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0; + virtual void setupProgram(Program* program) = 0; + + inline bool blend() const { + return mBlend; + } + + Type type() const { + return mType; + } + +protected: + Type mType; + bool mBlend; +}; // struct SkiaColorFilter + +/////////////////////////////////////////////////////////////////////////////// +// Implementations +/////////////////////////////////////////////////////////////////////////////// + +/** + * A color filter that multiplies the source color with a matrix and adds a vector. + */ +struct SkiaColorMatrixFilter: public SkiaColorFilter { + SkiaColorMatrixFilter(float* matrix, float* vector); + ~SkiaColorMatrixFilter(); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program); + +private: + float* mMatrix; + float* mVector; +}; // struct SkiaColorMatrixFilter + +/** + * A color filters that multiplies the source color with a fixed value and adds + * another fixed value. Ignores the alpha channel of both arguments. + */ +struct SkiaLightingFilter: public SkiaColorFilter { + SkiaLightingFilter(int multiply, int add); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program); + +private: + GLfloat mMulR, mMulG, mMulB; + GLfloat mAddR, mAddG, mAddB; +}; // struct SkiaLightingFilter + +/** + * A color filters that blends the source color with a specified destination color + * and PorterDuff blending mode. + */ +struct SkiaBlendFilter: public SkiaColorFilter { + SkiaBlendFilter(int color, SkXfermode::Mode mode); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program); + +private: + SkXfermode::Mode mMode; + GLfloat mR, mG, mB, mA; +}; // struct SkiaBlendFilter + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_SKIA_COLOR_FILTER_H diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp new file mode 100644 index 0000000..fa85d20 --- /dev/null +++ b/libs/hwui/SkiaShader.cpp @@ -0,0 +1,338 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <utils/Log.h> + +#include <SkMatrix.h> + +#include "SkiaShader.h" +#include "Texture.h" +#include "Matrix.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Support +/////////////////////////////////////////////////////////////////////////////// + +static const GLenum gTextureUnitsMap[] = { + GL_TEXTURE0, + GL_TEXTURE1, + GL_TEXTURE2 +}; + +static const GLint gTileModes[] = { + GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode + GL_REPEAT, // == SkShader::kRepeat_Mode + GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode +}; + +/////////////////////////////////////////////////////////////////////////////// +// Base shader +/////////////////////////////////////////////////////////////////////////////// + +SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, + SkShader::TileMode tileY, SkMatrix* matrix, bool blend): + mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) { + setMatrix(matrix); +} + +SkiaShader::~SkiaShader() { +} + +void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) { +} + +void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit) { +} + +void SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { + glActiveTexture(gTextureUnitsMap[textureUnit]); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); +} + +void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { + screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); + screenSpace.multiply(modelView); +} + +/////////////////////////////////////////////////////////////////////////////// +// Bitmap shader +/////////////////////////////////////////////////////////////////////////////// + +SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, + SkShader::TileMode tileY, SkMatrix* matrix, bool blend): + SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) { + updateLocalMatrix(matrix); +} + +void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { + const Texture* texture = mTextureCache->get(mBitmap); + if (!texture) return; + mTexture = texture; + + const float width = texture->width; + const float height = texture->height; + + description.hasBitmap = true; + // The driver does not support non-power of two mirrored/repeated + // textures, so do it ourselves + if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && + (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) { + description.isBitmapNpot = true; + description.bitmapWrapS = gTileModes[mTileX]; + description.bitmapWrapT = gTileModes[mTileY]; + mWrapS = GL_CLAMP_TO_EDGE; + mWrapT = GL_CLAMP_TO_EDGE; + } else { + mWrapS = gTileModes[mTileX]; + mWrapT = gTileModes[mTileY]; + } +} + +void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + GLuint textureSlot = (*textureUnit)++; + glActiveTexture(gTextureUnitsMap[textureSlot]); + + const Texture* texture = mTexture; + mTexture = NULL; + if (!texture) return; + const AutoTexture autoCleanup(texture); + + const float width = texture->width; + const float height = texture->height; + + mat4 textureTransform; + computeScreenSpaceMatrix(textureTransform, modelView); + + // Uniforms + bindTexture(texture->id, mWrapS, mWrapT, textureSlot); + glUniform1i(program->getUniform("bitmapSampler"), textureSlot); + glUniformMatrix4fv(program->getUniform("textureTransform"), 1, + GL_FALSE, &textureTransform.data[0]); + glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); +} + +void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView, + const Snapshot& snapshot) { + mat4 textureTransform; + computeScreenSpaceMatrix(textureTransform, modelView); + glUniformMatrix4fv(program->getUniform("textureTransform"), 1, + GL_FALSE, &textureTransform.data[0]); +} + +/////////////////////////////////////////////////////////////////////////////// +// Linear gradient shader +/////////////////////////////////////////////////////////////////////////////// + +static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { + SkVector vec = pts[1] - pts[0]; + const float mag = vec.length(); + const float inv = mag ? 1.0f / mag : 0; + + vec.scale(inv); + matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); + matrix->postTranslate(-pts[0].fX, -pts[0].fY); + matrix->postScale(inv, inv); +} + +SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors, + float* positions, int count, SkShader* key, SkShader::TileMode tileMode, + SkMatrix* matrix, bool blend): + SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend), + mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) { + SkPoint points[2]; + points[0].set(bounds[0], bounds[1]); + points[1].set(bounds[2], bounds[3]); + + SkMatrix unitMatrix; + toUnitMatrix(points, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); +} + +SkiaLinearGradientShader::~SkiaLinearGradientShader() { + delete[] mBounds; + delete[] mColors; + delete[] mPositions; +} + +void SkiaLinearGradientShader::describe(ProgramDescription& description, + const Extensions& extensions) { + description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientLinear; +} + +void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + GLuint textureSlot = (*textureUnit)++; + glActiveTexture(gTextureUnitsMap[textureSlot]); + + Texture* texture = mGradientCache->get(mKey); + if (!texture) { + texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX); + } + + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); + + // Uniforms + bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot); + glUniform1i(program->getUniform("gradientSampler"), textureSlot); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView, + const Snapshot& snapshot) { + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +/////////////////////////////////////////////////////////////////////////////// +// Circular gradient shader +/////////////////////////////////////////////////////////////////////////////// + +static void toCircularUnitMatrix(const float x, const float y, const float radius, + SkMatrix* matrix) { + const float inv = 1.0f / radius; + matrix->setTranslate(-x, -y); + matrix->postScale(inv, inv); +} + +SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, + uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, + SkMatrix* matrix, bool blend): + SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key, + tileMode, matrix, blend) { + SkMatrix unitMatrix; + toCircularUnitMatrix(x, y, radius, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); +} + +void SkiaCircularGradientShader::describe(ProgramDescription& description, + const Extensions& extensions) { + description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientCircular; +} + +/////////////////////////////////////////////////////////////////////////////// +// Sweep gradient shader +/////////////////////////////////////////////////////////////////////////////// + +static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { + matrix->setTranslate(-x, -y); +} + +SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, + float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): + SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, matrix, blend), + mColors(colors), mPositions(positions), mCount(count) { + SkMatrix unitMatrix; + toSweepUnitMatrix(x, y, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); +} + +SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, + float* positions, int count, SkShader* key, SkShader::TileMode tileMode, + SkMatrix* matrix, bool blend): + SkiaShader(type, key, tileMode, tileMode, matrix, blend), + mColors(colors), mPositions(positions), mCount(count) { +} + +SkiaSweepGradientShader::~SkiaSweepGradientShader() { + delete[] mColors; + delete[] mPositions; +} + +void SkiaSweepGradientShader::describe(ProgramDescription& description, + const Extensions& extensions) { + description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientSweep; +} + +void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + GLuint textureSlot = (*textureUnit)++; + glActiveTexture(gTextureUnitsMap[textureSlot]); + + Texture* texture = mGradientCache->get(mKey); + if (!texture) { + texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount); + } + + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); + + // Uniforms + bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot); + glUniform1i(program->getUniform("gradientSampler"), textureSlot); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, + const Snapshot& snapshot) { + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +/////////////////////////////////////////////////////////////////////////////// +// Compose shader +/////////////////////////////////////////////////////////////////////////////// + +SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, + SkXfermode::Mode mode, SkShader* key): + SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, + NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) { +} + +void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) { + SkiaShader::set(textureCache, gradientCache); + mFirst->set(textureCache, gradientCache); + mSecond->set(textureCache, gradientCache); +} + +void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) { + mFirst->describe(description, extensions); + mSecond->describe(description, extensions); + if (mFirst->type() == kBitmap) { + description.isBitmapFirst = true; + } + description.shadersMode = mMode; +} + +void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + mFirst->setupProgram(program, modelView, snapshot, textureUnit); + mSecond->setupProgram(program, modelView, snapshot, textureUnit); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h new file mode 100644 index 0000000..2565e65 --- /dev/null +++ b/libs/hwui/SkiaShader.h @@ -0,0 +1,215 @@ +/* + * 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_UI_SKIA_SHADER_H +#define ANDROID_UI_SKIA_SHADER_H + +#include <SkShader.h> +#include <SkXfermode.h> + +#include <GLES2/gl2.h> + +#include "Extensions.h" +#include "ProgramCache.h" +#include "TextureCache.h" +#include "GradientCache.h" +#include "Snapshot.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Base shader +/////////////////////////////////////////////////////////////////////////////// + +/** + * Represents a Skia shader. A shader will modify the GL context and active + * program to recreate the original effect. + */ +struct SkiaShader { + /** + * Type of Skia shader in use. + */ + enum Type { + kNone, + kBitmap, + kLinearGradient, + kCircularGradient, + kSweepGradient, + kCompose + }; + + SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY, + SkMatrix* matrix, bool blend); + virtual ~SkiaShader(); + + virtual void describe(ProgramDescription& description, const Extensions& extensions); + virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + + inline bool blend() const { + return mBlend; + } + + Type type() const { + return mType; + } + + virtual void set(TextureCache* textureCache, GradientCache* gradientCache) { + mTextureCache = textureCache; + mGradientCache = gradientCache; + } + + virtual void updateTransforms(Program* program, const mat4& modelView, + const Snapshot& snapshot) { + } + + void setMatrix(SkMatrix* matrix) { + updateLocalMatrix(matrix); + } + + void updateLocalMatrix(const SkMatrix* matrix) { + if (matrix) { + mat4 localMatrix(*matrix); + mShaderMatrix.loadInverse(localMatrix); + } else { + mShaderMatrix.loadIdentity(); + } + } + + void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView); + +protected: + inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit); + + Type mType; + SkShader* mKey; + SkShader::TileMode mTileX; + SkShader::TileMode mTileY; + bool mBlend; + + TextureCache* mTextureCache; + GradientCache* mGradientCache; + + mat4 mUnitMatrix; + mat4 mShaderMatrix; +}; // struct SkiaShader + + +/////////////////////////////////////////////////////////////////////////////// +// Implementations +/////////////////////////////////////////////////////////////////////////////// + +/** + * A shader that draws a bitmap. + */ +struct SkiaBitmapShader: public SkiaShader { + SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, + SkShader::TileMode tileY, SkMatrix* matrix, bool blend); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); + +private: + /** + * This method does not work for n == 0. + */ + inline bool isPowerOfTwo(unsigned int n) { + return !(n & (n - 1)); + } + + SkBitmap* mBitmap; + const Texture* mTexture; + GLenum mWrapS; + GLenum mWrapT; +}; // struct SkiaBitmapShader + +/** + * A shader that draws a linear gradient. + */ +struct SkiaLinearGradientShader: public SkiaShader { + SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count, + SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + ~SkiaLinearGradientShader(); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); + +private: + float* mBounds; + uint32_t* mColors; + float* mPositions; + int mCount; +}; // struct SkiaLinearGradientShader + +/** + * A shader that draws a sweep gradient. + */ +struct SkiaSweepGradientShader: public SkiaShader { + SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count, + SkShader* key, SkMatrix* matrix, bool blend); + ~SkiaSweepGradientShader(); + + virtual void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); + +protected: + SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, + int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + + uint32_t* mColors; + float* mPositions; + int mCount; +}; // struct SkiaSweepGradientShader + +/** + * A shader that draws a circular gradient. + */ +struct SkiaCircularGradientShader: public SkiaSweepGradientShader { + SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions, + int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + + void describe(ProgramDescription& description, const Extensions& extensions); +}; // struct SkiaCircularGradientShader + +/** + * A shader that draws two shaders, composited with an xfermode. + */ +struct SkiaComposeShader: public SkiaShader { + SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key); + + void set(TextureCache* textureCache, GradientCache* gradientCache); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + +private: + SkiaShader* mFirst; + SkiaShader* mSecond; + SkXfermode::Mode mMode; +}; // struct SkiaComposeShader + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_SKIA_SHADER_H diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h new file mode 100644 index 0000000..2da1950 --- /dev/null +++ b/libs/hwui/Snapshot.h @@ -0,0 +1,256 @@ +/* + * 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_UI_SNAPSHOT_H +#define ANDROID_UI_SNAPSHOT_H + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <utils/RefBase.h> + +#include <SkCanvas.h> +#include <SkRegion.h> + +#include "Layer.h" +#include "Matrix.h" +#include "Rect.h" + +namespace android { +namespace uirenderer { + +/** + * A snapshot holds information about the current state of the rendering + * surface. A snapshot is usually created whenever the user calls save() + * and discarded when the user calls restore(). Once a snapshot is created, + * it can hold information for deferred rendering. + * + * Each snapshot has a link to a previous snapshot, indicating the previous + * state of the renderer. + */ +class Snapshot: public LightRefBase<Snapshot> { +public: + Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) { + transform = &mTransformRoot; + clipRect = &mClipRectRoot; + } + + /** + * Copies the specified snapshot/ The specified snapshot is stored as + * the previous snapshot. + */ + Snapshot(const sp<Snapshot>& s, int saveFlags): + flags(0), previous(s), layer(NULL), fbo(s->fbo), + invisible(s->invisible), viewport(s->viewport), height(s->height) { + if (saveFlags & SkCanvas::kMatrix_SaveFlag) { + mTransformRoot.load(*s->transform); + transform = &mTransformRoot; + } else { + transform = s->transform; + } + + if (saveFlags & SkCanvas::kClip_SaveFlag) { + mClipRectRoot.set(*s->clipRect); + clipRect = &mClipRectRoot; + } else { + clipRect = s->clipRect; + } + + if ((s->flags & Snapshot::kFlagClipSet) && + !(s->flags & Snapshot::kFlagDirtyLocalClip)) { + mLocalClip.set(s->mLocalClip); + } else { + flags |= Snapshot::kFlagDirtyLocalClip; + } + } + + /** + * Various flags set on #flags. + */ + enum Flags { + /** + * Indicates that the clip region was modified. When this + * snapshot is restored so must the clip. + */ + kFlagClipSet = 0x1, + /** + * Indicates that this snapshot was created when saving + * a new layer. + */ + kFlagIsLayer = 0x2, + /** + * Indicates that this snapshot is a special type of layer + * backed by an FBO. This flag only makes sense when the + * flag kFlagIsLayer is also set. + */ + kFlagIsFboLayer = 0x4, + /** + * Indicates that the local clip should be recomputed. + */ + kFlagDirtyLocalClip = 0x8, + /** + * Indicates that this snapshot has changed the ortho matrix. + */ + kFlagDirtyOrtho = 0x10, + }; + + /** + * Modifies the current clip with the new clip rectangle and + * the specified operation. The specified rectangle is transformed + * by this snapshot's trasnformation. + */ + bool clip(float left, float top, float right, float bottom, + SkRegion::Op op = SkRegion::kIntersect_Op) { + Rect r(left, top, right, bottom); + transform->mapRect(r); + return clipTransformed(r, op); + } + + /** + * Modifies the current clip with the new clip rectangle and + * the specified operation. The specified rectangle is considered + * already transformed. + */ + bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op) { + bool clipped = false; + + // NOTE: The unimplemented operations require support for regions + // Supporting regions would require using a stencil buffer instead + // of the scissor. The stencil buffer itself is not too expensive + // (memory cost excluded) but on fillrate limited devices, managing + // the stencil might have a negative impact on the framerate. + switch (op) { + case SkRegion::kDifference_Op: + break; + case SkRegion::kIntersect_Op: + clipped = clipRect->intersect(r); + break; + case SkRegion::kUnion_Op: + clipped = clipRect->unionWith(r); + break; + case SkRegion::kXOR_Op: + break; + case SkRegion::kReverseDifference_Op: + break; + case SkRegion::kReplace_Op: + clipRect->set(r); + clipped = true; + break; + } + + if (clipped) { + flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + } + + return clipped; + } + + /** + * Sets the current clip. + */ + void setClip(float left, float top, float right, float bottom) { + clipRect->set(left, top, right, bottom); + flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + } + + const Rect& getLocalClip() { + if (flags & Snapshot::kFlagDirtyLocalClip) { + mat4 inverse; + inverse.loadInverse(*transform); + + mLocalClip.set(*clipRect); + inverse.mapRect(mLocalClip); + + flags &= ~Snapshot::kFlagDirtyLocalClip; + } + return mLocalClip; + } + + void resetTransform(float x, float y, float z) { + transform = &mTransformRoot; + transform->loadTranslate(x, y, z); + } + + void resetClip(float left, float top, float right, float bottom) { + clipRect = &mClipRectRoot; + clipRect->set(left, top, right, bottom); + flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip; + } + + /** + * Dirty flags. + */ + int flags; + + /** + * Previous snapshot. + */ + sp<Snapshot> previous; + + /** + * Only set when the flag kFlagIsLayer is set. + */ + Layer* layer; + + /** + * Only set when the flag kFlagIsFboLayer is set. + */ + GLuint fbo; + + /** + * Indicates that this snapshot is invisible and nothing should be drawn + * inside it. + */ + bool invisible; + + /** + * Current viewport. + */ + Rect viewport; + + /** + * Height of the framebuffer the snapshot is rendering into. + */ + int height; + + /** + * Contains the previous ortho matrix. + */ + mat4 orthoMatrix; + + /** + * Local transformation. Holds the current translation, scale and + * rotation values. + */ + mat4* transform; + + /** + * Current clip region. The clip is stored in canvas-space coordinates, + * (screen-space coordinates in the regular case.) + */ + Rect* clipRect; + +private: + mat4 mTransformRoot; + Rect mClipRectRoot; + Rect mLocalClip; + +}; // class Snapshot + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_SNAPSHOT_H diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp new file mode 100644 index 0000000..9d54277 --- /dev/null +++ b/libs/hwui/TextDropShadowCache.cpp @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include "TextDropShadowCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +TextDropShadowCache::TextDropShadowCache(): + mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting drop shadow cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE); + } + + mCache.setOnEntryRemovedListener(this); +} + +TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): + mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(maxByteSize) { + mCache.setOnEntryRemovedListener(this); +} + +TextDropShadowCache::~TextDropShadowCache() { + mCache.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t TextDropShadowCache::getSize() { + return mSize; +} + +uint32_t TextDropShadowCache::getMaxSize() { + return mMaxSize; +} + +void TextDropShadowCache::setMaxSize(uint32_t maxSize) { + mMaxSize = maxSize; + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +/////////////////////////////////////////////////////////////////////////////// + +void TextDropShadowCache::operator()(ShadowText& text, ShadowTexture*& texture) { + const uint32_t size = texture->width * texture->height; + mSize -= size; + + if (texture) { + glDeleteTextures(1, &texture->id); + delete texture; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void TextDropShadowCache::clear() { + mCache.clear(); +} + +ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, + int numGlyphs, uint32_t radius) { + ShadowText entry(paint, radius, len, text); + ShadowTexture* texture = mCache.get(entry); + + if (!texture) { + FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(paint, text, 0, + len, numGlyphs, radius); + + texture = new ShadowTexture; + texture->left = shadow.penX; + texture->top = shadow.penY; + texture->width = shadow.width; + texture->height = shadow.height; + texture->generation = 0; + texture->blend = true; + + const uint32_t size = shadow.width * shadow.height; + // Don't even try to cache a bitmap that's bigger than the cache + if (size < mMaxSize) { + while (mSize + size > mMaxSize) { + mCache.removeOldest(); + } + } + + glGenTextures(1, &texture->id); + + glBindTexture(GL_TEXTURE_2D, texture->id); + // Textures are Alpha8 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (size < mMaxSize) { + mSize += size; + mCache.put(entry, texture); + } else { + texture->cleanup = true; + } + + // Cleanup shadow + delete[] shadow.image; + } + + return texture; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h new file mode 100644 index 0000000..16e2814 --- /dev/null +++ b/libs/hwui/TextDropShadowCache.h @@ -0,0 +1,151 @@ +/* + * 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_UI_TEXT_DROP_SHADOW_CACHE_H +#define ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H + +#include <GLES2/gl2.h> + +#include <SkPaint.h> + +#include "utils/GenerationCache.h" +#include "FontRenderer.h" +#include "Texture.h" + +namespace android { +namespace uirenderer { + +struct ShadowText { + ShadowText() { + text = NULL; + } + + ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText): + radius(radius), len(len) { + text = new char[len]; + memcpy(text, srcText, len); + + textSize = paint->getTextSize(); + typeface = paint->getTypeface(); + + hash = 0; + uint32_t multiplier = 1; + for (uint32_t i = 0; i < len; i++) { + hash += text[i] * multiplier; + uint32_t shifted = multiplier << 5; + multiplier = shifted - multiplier; + } + } + + ShadowText(const ShadowText& shadow): + radius(shadow.radius), len(shadow.len), hash(shadow.hash), + textSize(shadow.textSize), typeface(shadow.typeface) { + text = new char[shadow.len]; + memcpy(text, shadow.text, shadow.len); + } + + ~ShadowText() { + delete[] text; + } + + uint32_t radius; + uint32_t len; + uint32_t hash; + float textSize; + SkTypeface* typeface; + char *text; + + bool operator<(const ShadowText& rhs) const { + if (hash < rhs.hash) return true; + else if (hash == rhs.hash) { + if (len < rhs.len) return true; + else if (len == rhs.len) { + if (radius < rhs.radius) return true; + else if (radius == rhs.radius) { + if (textSize < rhs.textSize) return true; + else if (textSize == rhs.textSize) { + if (typeface < rhs.typeface) return true; + else if (typeface == rhs.typeface) { + return strncmp(text, rhs.text, len) < 0; + } + } + } + } + } + return false; + } +}; // struct ShadowText + +/** + * Alpha texture used to represent a shadow. + */ +struct ShadowTexture: public Texture { + ShadowTexture(): Texture() { + } + + float left; + float top; +}; // struct ShadowTexture + +class TextDropShadowCache: public OnEntryRemoved<ShadowText, ShadowTexture*> { +public: + TextDropShadowCache(); + TextDropShadowCache(uint32_t maxByteSize); + ~TextDropShadowCache(); + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(ShadowText& text, ShadowTexture*& texture); + + ShadowTexture* get(SkPaint* paint, const char* text, uint32_t len, + int numGlyphs, uint32_t radius); + + /** + * Clears the cache. This causes all textures to be deleted. + */ + void clear(); + + void setFontRenderer(FontRenderer& fontRenderer) { + mRenderer = &fontRenderer; + } + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + GenerationCache<ShadowText, ShadowTexture*> mCache; + + uint32_t mSize; + uint32_t mMaxSize; + FontRenderer* mRenderer; +}; // class TextDropShadowCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h new file mode 100644 index 0000000..817f143 --- /dev/null +++ b/libs/hwui/Texture.h @@ -0,0 +1,81 @@ +/* + * 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_UI_TEXTURE_H +#define ANDROID_UI_TEXTURE_H + +#include <GLES2/gl2.h> + +namespace android { +namespace uirenderer { + +/** + * Represents an OpenGL texture. + */ +struct Texture { + Texture() { + cleanup = false; + bitmapSize = 0; + } + + /** + * Name of the texture. + */ + GLuint id; + /** + * Generation of the backing bitmap, + */ + uint32_t generation; + /** + * Indicates whether the texture requires blending. + */ + bool blend; + /** + * Width of the backing bitmap. + */ + uint32_t width; + /** + * Height of the backing bitmap. + */ + uint32_t height; + /** + * Indicates whether this texture should be cleaned up after use. + */ + bool cleanup; + /** + * Optional, size of the original bitmap. + */ + uint32_t bitmapSize; +}; // struct Texture + +class AutoTexture { +public: + AutoTexture(const Texture* texture): mTexture(texture) { } + ~AutoTexture() { + if (mTexture && mTexture->cleanup) { + glDeleteTextures(1, &mTexture->id); + delete mTexture; + } + } + +private: + const Texture* mTexture; +}; // class AutoTexture + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_TEXTURE_H diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp new file mode 100644 index 0000000..701df83 --- /dev/null +++ b/libs/hwui/TextureCache.cpp @@ -0,0 +1,237 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <GLES2/gl2.h> + +#include <SkCanvas.h> + +#include <utils/threads.h> + +#include "TextureCache.h" +#include "Properties.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Constructors/destructor +/////////////////////////////////////////////////////////////////////////////// + +TextureCache::TextureCache(): + mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { + LOGD(" Setting texture cache size to %sMB", property); + setMaxSize(MB(atof(property))); + } else { + LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); + } + + init(); +} + +TextureCache::TextureCache(uint32_t maxByteSize): + mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mSize(0), mMaxSize(maxByteSize) { + init(); +} + +TextureCache::~TextureCache() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +void TextureCache::init() { + mCache.setOnEntryRemovedListener(this); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize); +} + +/////////////////////////////////////////////////////////////////////////////// +// Size management +/////////////////////////////////////////////////////////////////////////////// + +uint32_t TextureCache::getSize() { + Mutex::Autolock _l(mLock); + return mSize; +} + +uint32_t TextureCache::getMaxSize() { + Mutex::Autolock _l(mLock); + return mMaxSize; +} + +void TextureCache::setMaxSize(uint32_t maxSize) { + Mutex::Autolock _l(mLock); + mMaxSize = maxSize; + while (mSize > mMaxSize) { + mCache.removeOldest(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks +/////////////////////////////////////////////////////////////////////////////// + +void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { + // This will be called already locked + if (texture) { + mSize -= texture->bitmapSize; + glDeleteTextures(1, &texture->id); + delete texture; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +Texture* TextureCache::get(SkBitmap* bitmap) { + mLock.lock(); + Texture* texture = mCache.get(bitmap); + mLock.unlock(); + + if (!texture) { + if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { + LOGW("Bitmap too large to be uploaded into a texture"); + return NULL; + } + + const uint32_t size = bitmap->rowBytes() * bitmap->height(); + // Don't even try to cache a bitmap that's bigger than the cache + if (size < mMaxSize) { + mLock.lock(); + while (mSize + size > mMaxSize) { + mCache.removeOldest(); + } + mLock.unlock(); + } + + texture = new Texture; + texture->bitmapSize = size; + generateTexture(bitmap, texture, false); + + if (size < mMaxSize) { + mLock.lock(); + mSize += size; + mCache.put(bitmap, texture); + mLock.unlock(); + } else { + texture->cleanup = true; + } + } else if (bitmap->getGenerationID() != texture->generation) { + generateTexture(bitmap, texture, true); + } + + return texture; +} + +void TextureCache::remove(SkBitmap* bitmap) { + Mutex::Autolock _l(mLock); + mCache.remove(bitmap); +} + +void TextureCache::clear() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) { + SkAutoLockPixels alp(*bitmap); + + if (!bitmap->readyToDraw()) { + LOGE("Cannot generate texture from bitmap"); + return; + } + + const bool resize = !regenerate || bitmap->width() != int(texture->width) || + bitmap->height() != int(texture->height); + + if (!regenerate) { + glGenTextures(1, &texture->id); + } + + texture->generation = bitmap->getGenerationID(); + texture->width = bitmap->width(); + texture->height = bitmap->height(); + + glBindTexture(GL_TEXTURE_2D, texture->id); + glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); + + switch (bitmap->getConfig()) { + case SkBitmap::kA8_Config: + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height, + GL_UNSIGNED_BYTE, bitmap->getPixels()); + texture->blend = true; + break; + case SkBitmap::kRGB_565_Config: + uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), texture->height, + GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels()); + texture->blend = false; + break; + case SkBitmap::kARGB_8888_Config: + uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, + GL_UNSIGNED_BYTE, bitmap->getPixels()); + // Do this after calling getPixels() to make sure Skia's deferred + // decoding happened + texture->blend = !bitmap->isOpaque(); + break; + case SkBitmap::kIndex8_Config: + uploadPalettedTexture(resize, bitmap, texture->width, texture->height); + texture->blend = false; + break; + default: + LOGW("Unsupported bitmap config: %d", bitmap->getConfig()); + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +void TextureCache::uploadPalettedTexture(bool resize, SkBitmap* bitmap, + uint32_t width, uint32_t height) { + SkBitmap rgbaBitmap; + rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + rgbaBitmap.allocPixels(); + rgbaBitmap.eraseColor(0); + + SkCanvas canvas(rgbaBitmap); + canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL); + + uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), height, + GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); +} + +void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height, + GLenum type, const GLvoid * data) { + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h new file mode 100644 index 0000000..467e851 --- /dev/null +++ b/libs/hwui/TextureCache.h @@ -0,0 +1,104 @@ +/* + * 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_UI_TEXTURE_CACHE_H +#define ANDROID_UI_TEXTURE_CACHE_H + +#include <SkBitmap.h> + +#include "Texture.h" +#include "utils/GenerationCache.h" + +namespace android { +namespace uirenderer { + +/** + * A simple LRU texture cache. The cache has a maximum size expressed in bytes. + * Any texture added to the cache causing the cache to grow beyond the maximum + * allowed size will also cause the oldest texture to be kicked out. + */ +class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> { +public: + TextureCache(); + TextureCache(uint32_t maxByteSize); + ~TextureCache(); + + /** + * Used as a callback when an entry is removed from the cache. + * Do not invoke directly. + */ + void operator()(SkBitmap*& bitmap, Texture*& texture); + + /** + * Returns the texture associated with the specified bitmap. If the texture + * cannot be found in the cache, a new texture is generated. + */ + Texture* get(SkBitmap* bitmap); + /** + * Removes the texture associated with the specified bitmap. Returns NULL + * if the texture cannot be found. Upon remove the texture is freed. + */ + void remove(SkBitmap* bitmap); + /** + * Clears the cache. This causes all textures to be deleted. + */ + void clear(); + + /** + * Sets the maximum size of the cache in bytes. + */ + void setMaxSize(uint32_t maxSize); + /** + * Returns the maximum size of the cache in bytes. + */ + uint32_t getMaxSize(); + /** + * Returns the current size of the cache in bytes. + */ + uint32_t getSize(); + +private: + /** + * Generates the texture from a bitmap into the specified texture structure. + * + * @param regenerate If true, the bitmap data is reuploaded into the texture, but + * no new texture is generated. + */ + void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false); + + void uploadPalettedTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height); + void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height, + GLenum type, const GLvoid * data); + + void init(); + + GenerationCache<SkBitmap*, Texture*> mCache; + + uint32_t mSize; + uint32_t mMaxSize; + GLint mMaxTextureSize; + + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ + mutable Mutex mLock; +}; // class TextureCache + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_TEXTURE_CACHE_H diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h new file mode 100644 index 0000000..1f54086 --- /dev/null +++ b/libs/hwui/Vertex.h @@ -0,0 +1,46 @@ +/* + * 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_UI_VERTEX_H +#define ANDROID_UI_VERTEX_H + +namespace android { +namespace uirenderer { + +/** + * Simple structure to describe a vertex with a position and a texture. + */ +struct TextureVertex { + float position[2]; + float texture[2]; + + static inline void set(TextureVertex* vertex, float x, float y, float u, float v) { + vertex[0].position[0] = x; + vertex[0].position[1] = y; + vertex[0].texture[0] = u; + vertex[0].texture[1] = v; + } + + static inline void setUV(TextureVertex* vertex, float u, float v) { + vertex[0].texture[0] = u; + vertex[0].texture[1] = v; + } +}; // struct TextureVertex + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_VERTEX_H diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h new file mode 100644 index 0000000..754b470 --- /dev/null +++ b/libs/hwui/utils/Compare.h @@ -0,0 +1,40 @@ +/* + * 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_UI_COMPARE_H +#define ANDROID_UI_COMPARE_H + +#include <cmath> + +#define EPSILON 0.00001f + +#define almost(u, v) (fabs((u) - (v)) < EPSILON) + +/** + * Compare floats. + */ +#define compare(a) \ + if (a < rhs.a) return true; \ + if (almost(a, rhs.a)) + +/** + * Compare integers. + */ +#define compareI(a) \ + if (a < rhs.a) return true; \ + if (a == rhs.a) + +#endif // ANDROID_UI_COMPARE_H diff --git a/libs/hwui/utils/GenerationCache.h b/libs/hwui/utils/GenerationCache.h new file mode 100644 index 0000000..5cea30f --- /dev/null +++ b/libs/hwui/utils/GenerationCache.h @@ -0,0 +1,245 @@ +/* + * 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_UI_GENERATION_CACHE_H +#define ANDROID_UI_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); +} + +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_UI_GENERATION_CACHE_H diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h new file mode 100644 index 0000000..68f5e9d --- /dev/null +++ b/libs/hwui/utils/SortedList.h @@ -0,0 +1,242 @@ +/* + * 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_UI_SORTED_LIST_H +#define ANDROID_UI_SORTED_LIST_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Vector.h> +#include <utils/TypeHelpers.h> + +#include "SortedListImpl.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Sorted list +/////////////////////////////////////////////////////////////////////////////// + +template<class TYPE> +class SortedList: private SortedListImpl { +public: + typedef TYPE value_type; + + SortedList(); + SortedList(const SortedList<TYPE>& rhs); + virtual ~SortedList(); + + const SortedList<TYPE>& operator =(const SortedList<TYPE>& rhs) const; + SortedList<TYPE>& operator =(const SortedList<TYPE>& rhs); + + inline void clear() { + VectorImpl::clear(); + } + + inline size_t size() const { + return VectorImpl::size(); + } + + inline bool isEmpty() const { + return VectorImpl::isEmpty(); + } + + inline size_t capacity() const { + return VectorImpl::capacity(); + } + + inline ssize_t setCapacity(size_t size) { + return VectorImpl::setCapacity(size); + } + + inline const TYPE* array() const; + + TYPE* editArray(); + + ssize_t indexOf(const TYPE& item) const; + size_t orderOf(const TYPE& item) const; + + inline const TYPE& operator [](size_t index) const; + inline const TYPE& itemAt(size_t index) const; + const TYPE& top() const; + const TYPE& mirrorItemAt(ssize_t index) const; + + ssize_t add(const TYPE& item); + + TYPE& editItemAt(size_t index) { + return *(static_cast<TYPE *> (VectorImpl::editItemLocation(index))); + } + + ssize_t merge(const Vector<TYPE>& vector); + ssize_t merge(const SortedList<TYPE>& vector); + + ssize_t remove(const TYPE&); + + inline ssize_t removeItemsAt(size_t index, size_t count = 1); + inline ssize_t removeAt(size_t index) { + return removeItemsAt(index); + } + +protected: + virtual void do_construct(void* storage, size_t num) const; + virtual void do_destroy(void* storage, size_t num) const; + virtual void do_copy(void* dest, const void* from, size_t num) const; + virtual void do_splat(void* dest, const void* item, size_t num) const; + virtual void do_move_forward(void* dest, const void* from, size_t num) const; + virtual void do_move_backward(void* dest, const void* from, size_t num) const; + virtual int do_compare(const void* lhs, const void* rhs) const; +}; // class SortedList + +/////////////////////////////////////////////////////////////////////////////// +// Implementation +/////////////////////////////////////////////////////////////////////////////// + +template<class TYPE> +inline SortedList<TYPE>::SortedList(): + SortedListImpl(sizeof(TYPE), ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0) + | (traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0) + | (traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))) { +} + +template<class TYPE> +inline SortedList<TYPE>::SortedList(const SortedList<TYPE>& rhs): SortedListImpl(rhs) { +} + +template<class TYPE> inline SortedList<TYPE>::~SortedList() { + finish_vector(); +} + +template<class TYPE> +inline SortedList<TYPE>& SortedList<TYPE>::operator =(const SortedList<TYPE>& rhs) { + SortedListImpl::operator =(rhs); + return *this; +} + +template<class TYPE> +inline const SortedList<TYPE>& SortedList<TYPE>::operator =( + const SortedList<TYPE>& rhs) const { + SortedListImpl::operator =(rhs); + return *this; +} + +template<class TYPE> +inline const TYPE* SortedList<TYPE>::array() const { + return static_cast<const TYPE *> (arrayImpl()); +} + +template<class TYPE> +inline TYPE* SortedList<TYPE>::editArray() { + return static_cast<TYPE *> (editArrayImpl()); +} + +template<class TYPE> +inline const TYPE& SortedList<TYPE>::operator[](size_t index) const { + assert( index<size() ); + return *(array() + index); +} + +template<class TYPE> +inline const TYPE& SortedList<TYPE>::itemAt(size_t index) const { + return operator[](index); +} + +template<class TYPE> +inline const TYPE& SortedList<TYPE>::mirrorItemAt(ssize_t index) const { + assert( (index>0 ? index : -index)<size() ); + return *(array() + ((index < 0) ? (size() - index) : index)); +} + +template<class TYPE> +inline const TYPE& SortedList<TYPE>::top() const { + return *(array() + size() - 1); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::add(const TYPE& item) { + return SortedListImpl::add(&item); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::indexOf(const TYPE& item) const { + return SortedListImpl::indexOf(&item); +} + +template<class TYPE> +inline size_t SortedList<TYPE>::orderOf(const TYPE& item) const { + return SortedListImpl::orderOf(&item); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::merge(const Vector<TYPE>& vector) { + return SortedListImpl::merge(reinterpret_cast<const VectorImpl&> (vector)); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::merge(const SortedList<TYPE>& vector) { + return SortedListImpl::merge(reinterpret_cast<const SortedListImpl&> (vector)); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::remove(const TYPE& item) { + return SortedListImpl::remove(&item); +} + +template<class TYPE> +inline ssize_t SortedList<TYPE>::removeItemsAt(size_t index, size_t count) { + return VectorImpl::removeItemsAt(index, count); +} + +template<class TYPE> +void SortedList<TYPE>::do_construct(void* storage, size_t num) const { + construct_type(reinterpret_cast<TYPE*> (storage), num); +} + +template<class TYPE> +void SortedList<TYPE>::do_destroy(void* storage, size_t num) const { + destroy_type(reinterpret_cast<TYPE*> (storage), num); +} + +template<class TYPE> +void SortedList<TYPE>::do_copy(void* dest, const void* from, size_t num) const { + copy_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num); +} + +template<class TYPE> +void SortedList<TYPE>::do_splat(void* dest, const void* item, size_t num) const { + splat_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (item), num); +} + +template<class TYPE> +void SortedList<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const { + move_forward_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num); +} + +template<class TYPE> +void SortedList<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const { + move_backward_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num); +} + +template<class TYPE> +int SortedList<TYPE>::do_compare(const void* lhs, const void* rhs) const { + return compare_type(*reinterpret_cast<const TYPE*> (lhs), *reinterpret_cast<const TYPE*> (rhs)); +} + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_SORTED_LIST_H diff --git a/libs/hwui/utils/SortedListImpl.cpp b/libs/hwui/utils/SortedListImpl.cpp new file mode 100644 index 0000000..35171d5 --- /dev/null +++ b/libs/hwui/utils/SortedListImpl.cpp @@ -0,0 +1,126 @@ +/* + * 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. + */ + +#include "SortedListImpl.h" + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Sorted list implementation, not for direct use +/////////////////////////////////////////////////////////////////////////////// + +SortedListImpl::SortedListImpl(size_t itemSize, uint32_t flags): VectorImpl(itemSize, flags) { +} + +SortedListImpl::SortedListImpl(const VectorImpl& rhs): VectorImpl(rhs) { +} + +SortedListImpl::~SortedListImpl() { +} + +SortedListImpl& SortedListImpl::operator =(const SortedListImpl& rhs) { + return static_cast<SortedListImpl&> + (VectorImpl::operator =(static_cast<const VectorImpl&> (rhs))); +} + +ssize_t SortedListImpl::indexOf(const void* item) const { + return _indexOrderOf(item); +} + +size_t SortedListImpl::orderOf(const void* item) const { + size_t o; + _indexOrderOf(item, &o); + return o; +} + +ssize_t SortedListImpl::_indexOrderOf(const void* item, size_t* order) const { + // binary search + ssize_t err = NAME_NOT_FOUND; + ssize_t l = 0; + ssize_t h = size() - 1; + ssize_t mid; + const void* a = arrayImpl(); + const size_t s = itemSize(); + while (l <= h) { + mid = l + (h - l) / 2; + const void* const curr = reinterpret_cast<const char *> (a) + (mid * s); + const int c = do_compare(curr, item); + if (c == 0) { + err = l = mid; + break; + } else if (c < 0) { + l = mid + 1; + } else { + h = mid - 1; + } + } + if (order) { + *order = l; + } + return err; +} + +ssize_t SortedListImpl::add(const void* item) { + size_t order; + ssize_t index = _indexOrderOf(item, &order); + index = VectorImpl::insertAt(item, order, 1); + return index; +} + +ssize_t SortedListImpl::merge(const VectorImpl& vector) { + // naive merge... + if (!vector.isEmpty()) { + const void* buffer = vector.arrayImpl(); + const size_t is = itemSize(); + size_t s = vector.size(); + for (size_t i = 0; i < s; i++) { + ssize_t err = add(reinterpret_cast<const char*> (buffer) + i * is); + if (err < 0) { + return err; + } + } + } + return NO_ERROR; +} + +ssize_t SortedListImpl::merge(const SortedListImpl& vector) { + // we've merging a sorted vector... nice! + ssize_t err = NO_ERROR; + if (!vector.isEmpty()) { + // first take care of the case where the vectors are sorted together + if (do_compare(vector.itemLocation(vector.size() - 1), arrayImpl()) <= 0) { + err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&> (vector), 0); + } else if (do_compare(vector.arrayImpl(), itemLocation(size() - 1)) >= 0) { + err = VectorImpl::appendVector(static_cast<const VectorImpl&> (vector)); + } else { + // this could be made a little better + err = merge(static_cast<const VectorImpl&> (vector)); + } + } + return err; +} + +ssize_t SortedListImpl::remove(const void* item) { + ssize_t i = indexOf(item); + if (i >= 0) { + VectorImpl::removeItemsAt(i, 1); + } + return i; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h new file mode 100644 index 0000000..7da09ef --- /dev/null +++ b/libs/hwui/utils/SortedListImpl.h @@ -0,0 +1,65 @@ +/* + * 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_UI_SORTED_LIST_IMPL_H +#define ANDROID_UI_SORTED_LIST_IMPL_H + +#include <utils/VectorImpl.h> + +namespace android { +namespace uirenderer { + +class SortedListImpl: public VectorImpl { +public: + SortedListImpl(size_t itemSize, uint32_t flags); + SortedListImpl(const VectorImpl& rhs); + virtual ~SortedListImpl(); + + SortedListImpl& operator =(const SortedListImpl& rhs); + + ssize_t indexOf(const void* item) const; + size_t orderOf(const void* item) const; + ssize_t add(const void* item); + ssize_t merge(const VectorImpl& vector); + ssize_t merge(const SortedListImpl& vector); + ssize_t remove(const void* item); + +protected: + virtual int do_compare(const void* lhs, const void* rhs) const = 0; + +private: + ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; + + // these are made private, because they can't be used on a SortedVector + // (they don't have an implementation either) + ssize_t add(); + void pop(); + void push(); + void push(const void* item); + ssize_t insertVectorAt(const VectorImpl& vector, size_t index); + ssize_t appendVector(const VectorImpl& vector); + ssize_t insertArrayAt(const void* array, size_t index, size_t length); + ssize_t appendArray(const void* array, size_t length); + ssize_t insertAt(size_t where, size_t numItems = 1); + ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); + ssize_t replaceAt(size_t index); + ssize_t replaceAt(const void* item, size_t index); +}; + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_UI_SORTED_LIST_IMPL_H diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 98464a0..05c1a48 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -76,34 +76,43 @@ ifneq ($(TARGET_SIMULATOR),true) LOCAL_SRC_FILES:= \ rsAdapter.cpp \ rsAllocation.cpp \ + rsAnimation.cpp \ rsComponent.cpp \ rsContext.cpp \ rsDevice.cpp \ rsElement.cpp \ - rsFileA3D.cpp \ - rsLight.cpp \ + rsFileA3D.cpp \ + rsFont.cpp \ rsLocklessFifo.cpp \ rsObjectBase.cpp \ rsMatrix.cpp \ - rsMesh.cpp \ - rsNoise.cpp \ + rsMesh.cpp \ + rsMutex.cpp \ rsProgram.cpp \ rsProgramFragment.cpp \ - rsProgramFragmentStore.cpp \ + rsProgramStore.cpp \ rsProgramRaster.cpp \ rsProgramVertex.cpp \ rsSampler.cpp \ rsScript.cpp \ rsScriptC.cpp \ rsScriptC_Lib.cpp \ - rsShaderCache.cpp \ - rsSimpleMesh.cpp \ + rsScriptC_LibCL.cpp \ + rsScriptC_LibGL.cpp \ + rsShaderCache.cpp \ + rsSignal.cpp \ + rsStream.cpp \ rsThreadIO.cpp \ rsType.cpp \ rsVertexArray.cpp -LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libacc +LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc + +LOCAL_STATIC_LIBRARIES := libft2 + +LOCAL_C_INCLUDES += external/freetype/include + LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libRS LOCAL_MODULE_TAGS := optional diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h index d280f50..e63cc9b 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/RenderScript.h @@ -27,23 +27,27 @@ extern "C" { ////////////////////////////////////////////////////// // +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 * RsSimpleMesh; +typedef void * RsMesh; typedef void * RsType; -typedef void * RsLight; +typedef void * RsObjectBase; typedef void * RsProgram; typedef void * RsProgramVertex; typedef void * RsProgramFragment; -typedef void * RsProgramFragmentStore; +typedef void * RsProgramStore; typedef void * RsProgramRaster; typedef void (* RsBitmapCallback_t)(void *); @@ -53,14 +57,27 @@ enum RsDeviceParam { 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, bool useDepth); +RsContext rsContextCreateGL(RsDevice, uint32_t version, RsSurfaceConfig sc); void rsContextDestroy(RsContext); -void rsObjDestroyOOB(RsContext, void *); uint32_t rsContextGetMessage(RsContext, void *data, size_t *receiveLen, size_t bufferLen, bool wait); void rsContextInitToClient(RsContext); @@ -83,11 +100,17 @@ enum RsDataType { 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_ELEMENT, + 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, @@ -96,24 +119,17 @@ enum RsDataType { RS_TYPE_PROGRAM_FRAGMENT, RS_TYPE_PROGRAM_VERTEX, RS_TYPE_PROGRAM_RASTER, - RS_TYPE_PROGRAM_STORE + RS_TYPE_PROGRAM_STORE, }; enum RsDataKind { RS_KIND_USER, - RS_KIND_COLOR, - RS_KIND_POSITION, - RS_KIND_TEXTURE, - RS_KIND_NORMAL, - RS_KIND_INDEX, - RS_KIND_POINT_SIZE, - - RS_KIND_PIXEL_L, + + RS_KIND_PIXEL_L = 7, RS_KIND_PIXEL_A, RS_KIND_PIXEL_LA, RS_KIND_PIXEL_RGB, RS_KIND_PIXEL_RGBA, - }; enum RsSamplerParam { @@ -121,7 +137,8 @@ enum RsSamplerParam { RS_SAMPLER_MAG_FILTER, RS_SAMPLER_WRAP_S, RS_SAMPLER_WRAP_T, - RS_SAMPLER_WRAP_R + RS_SAMPLER_WRAP_R, + RS_SAMPLER_ANISO }; enum RsSamplerValue { @@ -205,9 +222,76 @@ enum RsPrimitive { enum RsError { RS_ERROR_NONE, RS_ERROR_BAD_SHADER, - RS_ERROR_BAD_SCRIPT + RS_ERROR_BAD_SCRIPT, + RS_ERROR_BAD_VALUE, + RS_ERROR_OUT_OF_MEMORY +}; + +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; + + +// Async commands for returning new IDS +void * rsaTypeCreate(RsContext, RsElement, uint32_t dimCount, + const RsDimension *dims, const uint32_t *vals); + + #ifndef NO_RS_FUNCS #include "rsgApiFuncDecl.h" #endif diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h index 99b8c04..b82eaf1 100644 --- a/libs/rs/RenderScriptEnv.h +++ b/libs/rs/RenderScriptEnv.h @@ -9,12 +9,10 @@ typedef void * RsDevice; typedef void * RsElement; typedef void * RsSampler; typedef void * RsScript; -typedef void * RsSimpleMesh; +typedef void * RsMesh; typedef void * RsType; typedef void * RsProgramFragment; -typedef void * RsProgramFragmentStore; -typedef void * RsLight; - +typedef void * RsProgramStore; typedef struct { float m[16]; @@ -28,4 +26,4 @@ typedef struct { #define RS_PROGRAM_VERTEX_MODELVIEW_OFFSET 0 #define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16 #define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32 - +#define RS_PROGRAM_VERTEX_MVP_OFFSET 48 diff --git a/libs/rs/java/Film/res/drawable/p01.png b/libs/rs/java/Film/res/drawable/p01.png Binary files differdeleted file mode 100644 index a9b9bdb..0000000 --- a/libs/rs/java/Film/res/drawable/p01.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p02.png b/libs/rs/java/Film/res/drawable/p02.png Binary files differdeleted file mode 100644 index 8162c82..0000000 --- a/libs/rs/java/Film/res/drawable/p02.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p03.png b/libs/rs/java/Film/res/drawable/p03.png Binary files differdeleted file mode 100644 index e3e26c0..0000000 --- a/libs/rs/java/Film/res/drawable/p03.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p04.png b/libs/rs/java/Film/res/drawable/p04.png Binary files differdeleted file mode 100644 index daee603..0000000 --- a/libs/rs/java/Film/res/drawable/p04.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p05.png b/libs/rs/java/Film/res/drawable/p05.png Binary files differdeleted file mode 100644 index fac5248..0000000 --- a/libs/rs/java/Film/res/drawable/p05.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p06.png b/libs/rs/java/Film/res/drawable/p06.png Binary files differdeleted file mode 100644 index 3b51261..0000000 --- a/libs/rs/java/Film/res/drawable/p06.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p07.png b/libs/rs/java/Film/res/drawable/p07.png Binary files differdeleted file mode 100644 index d8bd938..0000000 --- a/libs/rs/java/Film/res/drawable/p07.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p08.png b/libs/rs/java/Film/res/drawable/p08.png Binary files differdeleted file mode 100644 index ef175e8..0000000 --- a/libs/rs/java/Film/res/drawable/p08.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p09.png b/libs/rs/java/Film/res/drawable/p09.png Binary files differdeleted file mode 100644 index 7bf3874..0000000 --- a/libs/rs/java/Film/res/drawable/p09.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p10.png b/libs/rs/java/Film/res/drawable/p10.png Binary files differdeleted file mode 100644 index 908827d..0000000 --- a/libs/rs/java/Film/res/drawable/p10.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p11.png b/libs/rs/java/Film/res/drawable/p11.png Binary files differdeleted file mode 100644 index 1289f71..0000000 --- a/libs/rs/java/Film/res/drawable/p11.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p12.png b/libs/rs/java/Film/res/drawable/p12.png Binary files differdeleted file mode 100644 index e1af16a..0000000 --- a/libs/rs/java/Film/res/drawable/p12.png +++ /dev/null diff --git a/libs/rs/java/Film/res/drawable/p13.png b/libs/rs/java/Film/res/drawable/p13.png Binary files differdeleted file mode 100644 index d08bcbe..0000000 --- a/libs/rs/java/Film/res/drawable/p13.png +++ /dev/null diff --git a/libs/rs/java/Film/res/raw/filmimage.c b/libs/rs/java/Film/res/raw/filmimage.c deleted file mode 100644 index d154c68..0000000 --- a/libs/rs/java/Film/res/raw/filmimage.c +++ /dev/null @@ -1,110 +0,0 @@ -// Fountain test script - -#pragma version(1) -#pragma stateVertex(orthoWindow) -#pragma stateRaster(flat) -#pragma stateFragment(PgmFragBackground) -#pragma stateStore(MyBlend) - - -int main(void* con, int ft, int launchID) { - int count, touch, x, y, rate, maxLife, lifeShift; - int life; - int ct, ct2; - int newPart; - int drawCount; - int dx, dy, idx; - int posx,posy; - int c; - int srcIdx; - int dstIdx; - - count = loadI32(con, 0, 1); - touch = loadI32(con, 0, 2); - x = loadI32(con, 0, 3); - y = loadI32(con, 0, 4); - - rate = 4; - maxLife = (count / rate) - 1; - lifeShift = 0; - { - life = maxLife; - while (life > 255) { - life = life >> 1; - lifeShift ++; - } - } - - drawRect(con, 0, 256, 0, 512); - contextBindProgramFragment(con, NAMED_PgmFragParts); - - if (touch) { - newPart = loadI32(con, 2, 0); - for (ct2=0; ct2<rate; ct2++) { - dx = scriptRand(con, 0x10000) - 0x8000; - dy = scriptRand(con, 0x10000) - 0x8000; - - idx = newPart * 5 + 1; - storeI32(con, 2, idx, dx); - storeI32(con, 2, idx + 1, dy); - storeI32(con, 2, idx + 2, maxLife); - storeI32(con, 2, idx + 3, x << 16); - storeI32(con, 2, idx + 4, y << 16); - - newPart++; - if (newPart >= count) { - newPart = 0; - } - } - storeI32(con, 2, 0, newPart); - } - - drawCount = 0; - for (ct=0; ct < count; ct++) { - srcIdx = ct * 5 + 1; - - dx = loadI32(con, 2, srcIdx); - dy = loadI32(con, 2, srcIdx + 1); - life = loadI32(con, 2, srcIdx + 2); - posx = loadI32(con, 2, srcIdx + 3); - posy = loadI32(con, 2, srcIdx + 4); - - if (life) { - if (posy < (480 << 16)) { - dstIdx = drawCount * 9; - c = 0xffafcf | ((life >> lifeShift) << 24); - - storeU32(con, 1, dstIdx, c); - storeI32(con, 1, dstIdx + 1, posx); - storeI32(con, 1, dstIdx + 2, posy); - - storeU32(con, 1, dstIdx + 3, c); - storeI32(con, 1, dstIdx + 4, posx + 0x10000); - storeI32(con, 1, dstIdx + 5, posy + dy * 4); - - storeU32(con, 1, dstIdx + 6, c); - storeI32(con, 1, dstIdx + 7, posx - 0x10000); - storeI32(con, 1, dstIdx + 8, posy + dy * 4); - drawCount ++; - } else { - if (dy > 0) { - dy = (-dy) >> 1; - } - } - - posx = posx + dx; - posy = posy + dy; - dy = dy + 0x400; - life --; - - //storeI32(con, 2, srcIdx, dx); - storeI32(con, 2, srcIdx + 1, dy); - storeI32(con, 2, srcIdx + 2, life); - storeI32(con, 2, srcIdx + 3, posx); - storeI32(con, 2, srcIdx + 4, posy); - } - } - - drawTriangleArray(con, NAMED_PartBuffer, drawCount); - return 1; -} diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c deleted file mode 100644 index bf75675..0000000 --- a/libs/rs/java/Film/res/raw/filmstrip.c +++ /dev/null @@ -1,94 +0,0 @@ -// Fountain test script - -#pragma version(1) -#pragma stateVertex(PVBackground) -#pragma stateFragment(PFBackground) -#pragma stateStore(PSBackground) - -#define STATE_TRIANGLE_OFFSET_COUNT 0 -#define STATE_LAST_FOCUS 1 - - -// The script enviroment has 3 env allocations. -// bank0: (r) The enviroment structure -// bank1: (r) The position information -// bank2: (rw) The temporary texture state - -int lastFocus; - -int main(int index) -{ - float mat1[16]; - - float trans = Pos->translate; - float rot = Pos->rotate; - - matrixLoadScale(mat1, 2.f, 2.f, 2.f); - matrixTranslate(mat1, 0.f, 0.f, trans); - matrixRotate(mat1, 90.f, 0.f, 0.f, 1.f); - matrixRotate(mat1, rot, 1.f, 0.f, 0.f); - vpLoadModelMatrix(mat1); - - // Draw the lighting effect in the strip and fill the Z buffer. - drawSimpleMesh(NAMED_mesh); - - // Start of images. - bindProgramStore(NAMED_PSImages); - bindProgramFragment(NAMED_PFImages); - bindProgramVertex(NAMED_PVImages); - - float focusPos = Pos->focus; - int focusID = 0; - int lastFocusID = loadI32(2, STATE_LAST_FOCUS); - int imgCount = 13; - - if (trans > (-.3f)) { - focusID = -1.0f - focusPos; - if (focusID >= imgCount) { - focusID = -1; - } - } else { - focusID = -1; - } - - /* - if (focusID != lastFocusID) { - if (lastFocusID >= 0) { - uploadToTexture(con, env->tex[lastFocusID], 1); - } - if (focusID >= 0) { - uploadToTexture(con, env->tex[focusID], 0); - } - } - */ - lastFocus = focusID; - - int triangleOffsetsCount = Pos->triangleOffsetCount; - - int imgId = 0; - for (imgId=1; imgId <= imgCount; imgId++) { - float pos = focusPos + imgId + 0.4f; - int offset = (int)floorf(pos * 2.f); - pos = pos - 0.75f; - - offset = offset + triangleOffsetsCount / 2; - if (!((offset < 0) || (offset >= triangleOffsetsCount))) { - int start = offset -2; - int end = offset + 2; - - if (start < 0) { - start = 0; - } - if (end >= triangleOffsetsCount) { - end = triangleOffsetsCount-1; - } - - bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1)); - matrixLoadTranslate(mat1, -pos - loadF(5, triangleOffsetsCount / 2), 0, 0); - vpLoadTextureMatrix(mat1); - drawSimpleMeshRange(NAMED_mesh, loadI32(4, start), (loadI32(4, end) - loadI32(4, start))); - } - } - return 0; -} - diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java deleted file mode 100644 index 7d04502..0000000 --- a/libs/rs/java/Film/src/com/android/film/FilmRS.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -package com.android.film; - -import java.io.Writer; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.util.Log; - -import android.renderscript.*; - -public class FilmRS { - class StripPosition { - public float translate; - public float rotate; - public float focus; - public int triangleOffsetCount; - } - StripPosition mPos = new StripPosition(); - - - private final int STATE_LAST_FOCUS = 1; - - public FilmRS() { - } - - public void init(RenderScriptGL rs, Resources res, int width, int height) { - mRS = rs; - mRes = res; - initRS(); - } - - public void setFilmStripPosition(int x, int y) - { - if (x < 50) { - x = 50; - } - if (x > 270) { - x = 270; - } - - float anim = ((float)x-50) / 270.f; - mPos.translate = 2f * anim + 0.5f; // translation - mPos.rotate = (anim * 40); // rotation - mPos.focus = ((float)y) / 16.f - 10.f; // focusPos - mPos.triangleOffsetCount = mFSM.mTriangleOffsetsCount; - mAllocPos.data(mPos); - } - - - private Resources mRes; - private RenderScriptGL mRS; - private Script mScriptStrip; - private Script mScriptImage; - private Sampler mSampler; - private ProgramStore mPSBackground; - private ProgramStore mPSImages; - private ProgramFragment mPFBackground; - private ProgramFragment mPFImages; - private ProgramVertex mPVBackground; - private ProgramVertex mPVImages; - private ProgramVertex.MatrixAllocation mPVA; - private Type mStripPositionType; - - private Allocation mImages[]; - private Allocation mAllocIDs; - private Allocation mAllocPos; - private Allocation mAllocState; - private Allocation mAllocPV; - private Allocation mAllocOffsetsTex; - private Allocation mAllocOffsets; - - private SimpleMesh mMesh; - private Light mLight; - - private FilmStripMesh mFSM; - - private int[] mBufferIDs; - private float[] mBufferPos = new float[3]; - private int[] mBufferState; - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS, null, null); - - b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnable(true); - b.setDepthMask(true); - mPSBackground = b.create(); - mPSBackground.setName("PSBackground"); - - b.setDepthFunc(ProgramStore.DepthFunc.EQUAL); - b.setDitherEnable(false); - b.setDepthMask(false); - b.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, - ProgramStore.BlendDstFunc.ONE); - mPSImages = b.create(); - mPSImages.setName("PSImages"); - } - - private void initPF() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR); - bs.setMag(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.CLAMP); - bs.setWrapT(Sampler.Value.WRAP); - mSampler = bs.create(); - - ProgramFragment.Builder b = new ProgramFragment.Builder(mRS); - mPFBackground = b.create(); - mPFBackground.setName("PFBackground"); - - b = new ProgramFragment.Builder(mRS); - b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, - ProgramFragment.Builder.Format.RGBA, 0); - mPFImages = b.create(); - mPFImages.bindSampler(mSampler, 0); - mPFImages.setName("PFImages"); - } - - private void initPV() { - mLight = (new Light.Builder(mRS)).create(); - mLight.setPosition(0, -0.5f, -1.0f); - - ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); - //pvb.addLight(mLight); - mPVBackground = pvb.create(); - mPVBackground.setName("PVBackground"); - - pvb = new ProgramVertex.Builder(mRS, null, null); - pvb.setTextureMatrixEnable(true); - mPVImages = pvb.create(); - mPVImages.setName("PVImages"); - } - - private void loadImages() { - mBufferIDs = new int[13]; - mImages = new Allocation[13]; - mAllocIDs = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.FLOAT_32), - mBufferIDs.length); - - Element ie = Element.createPixel(mRS, Element.DataType.UNSIGNED_5_6_5, Element.DataKind.PIXEL_RGB); - mImages[0] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p01, ie, true); - mImages[1] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p02, ie, true); - mImages[2] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p03, ie, true); - mImages[3] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p04, ie, true); - mImages[4] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p05, ie, true); - mImages[5] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p06, ie, true); - mImages[6] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p07, ie, true); - mImages[7] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p08, ie, true); - mImages[8] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p09, ie, true); - mImages[9] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p10, ie, true); - mImages[10] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p11, ie, true); - mImages[11] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p12, ie, true); - mImages[12] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p13, ie, true); - - int black[] = new int[1024]; - for(int ct=0; ct < mImages.length; ct++) { - Allocation.Adapter2D a = mImages[ct].createAdapter2D(); - - int size = 512; - int mip = 0; - while(size >= 2) { - a.subData(0, 0, 2, size, black); - a.subData(size-2, 0, 2, size, black); - a.subData(0, 0, size, 2, black); - a.subData(0, size-2, size, 2, black); - size >>= 1; - mip++; - a.setConstraint(Dimension.LOD, mip); - } - - mImages[ct].uploadToTexture(1); - mBufferIDs[ct] = mImages[ct].getID(); - } - mAllocIDs.data(mBufferIDs); - } - - private void initState() - { - mBufferState = new int[10]; - mAllocState = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.FLOAT_32), - mBufferState.length); - mBufferState[STATE_LAST_FOCUS] = -1; - mAllocState.data(mBufferState); - } - - private void initRS() { - mFSM = new FilmStripMesh(); - mMesh = mFSM.init(mRS); - mMesh.setName("mesh"); - - initPFS(); - initPF(); - initPV(); - - Log.e("rs", "Done loading named"); - - mStripPositionType = Type.createFromClass(mRS, StripPosition.class, 1); - - ScriptC.Builder sb = new ScriptC.Builder(mRS); - sb.setScript(mRes, R.raw.filmstrip); - sb.setRoot(true); - sb.setType(mStripPositionType, "Pos", 1); - mScriptStrip = sb.create(); - mScriptStrip.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - mAllocPos = Allocation.createTyped(mRS, mStripPositionType); - - loadImages(); - initState(); - - mPVA = new ProgramVertex.MatrixAllocation(mRS); - mPVBackground.bindAllocation(mPVA); - mPVImages.bindAllocation(mPVA); - mPVA.setupProjectionNormalized(320, 480); - - - mScriptStrip.bindAllocation(mAllocIDs, 0); - mScriptStrip.bindAllocation(mAllocPos, 1); - mScriptStrip.bindAllocation(mAllocState, 2); - mScriptStrip.bindAllocation(mPVA.mAlloc, 3); - - - mAllocOffsets = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.SIGNED_32), mFSM.mTriangleOffsets.length); - mAllocOffsets.data(mFSM.mTriangleOffsets); - mScriptStrip.bindAllocation(mAllocOffsets, 4); - - mAllocOffsetsTex = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.FLOAT_32), mFSM.mTriangleOffsetsTex.length); - mAllocOffsetsTex.data(mFSM.mTriangleOffsetsTex); - mScriptStrip.bindAllocation(mAllocOffsetsTex, 5); - - setFilmStripPosition(0, 0); - mRS.contextBindRootScript(mScriptStrip); - } -} - - - diff --git a/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java deleted file mode 100644 index 448cce0..0000000 --- a/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java +++ /dev/null @@ -1,259 +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. - */ - - -package com.android.film; - -import java.io.Writer; -import java.lang.Math; -import android.util.Log; - -import android.renderscript.RenderScript; -import android.renderscript.SimpleMesh; - - -class FilmStripMesh { - - class Vertex { - float nx; - float ny; - float nz; - float s; - float t; - float x; - float y; - float z; - - Vertex() { - nx = 0; - ny = 0; - nz = 0; - s = 0; - t = 0; - x = 0; - y = 0; - z = 0; - } - - void xyz(float _x, float _y, float _z) { - x = _x; - y = _y; - z = _z; - } - - void nxyz(float _x, float _y, float _z) { - nx = _x; - ny = _y; - nz = _z; - } - - void st(float _s, float _t) { - s = _s; - t = _t; - } - - void computeNorm(Vertex v1, Vertex v2) { - float dx = v1.x - v2.x; - float dy = v1.y - v2.y; - float dz = v1.z - v2.z; - float len = (float)java.lang.Math.sqrt(dx*dx + dy*dy + dz*dz); - dx /= len; - dy /= len; - dz /= len; - - nx = dx * dz; - ny = dy * dz; - nz = (float)java.lang.Math.sqrt(dx*dx + dy*dy); - - len = (float)java.lang.Math.sqrt(nx*nx + ny*ny + nz*nz); - nx /= len; - ny /= len; - nz /= len; - } - } - - int[] mTriangleOffsets; - float[] mTriangleOffsetsTex; - int mTriangleOffsetsCount; - - SimpleMesh init(RenderScript rs) - { - float vtx[] = new float[] { - 60.431003f, 124.482050f, - 60.862074f, 120.872604f, - 61.705303f, 117.336662f, - 62.949505f, 113.921127f, - 64.578177f, 110.671304f, - 66.569716f, 107.630302f, - 68.897703f, 104.838457f, - 71.531259f, 102.332803f, - 74.435452f, 100.146577f, - 77.571757f, 98.308777f, - 80.898574f, 96.843781f, - 84.371773f, 95.771023f, - 87.945283f, 95.104731f, - 98.958994f, 95.267098f, - 109.489523f, 98.497596f, - 118.699582f, 104.539366f, - 125.856872f, 112.912022f, - 130.392311f, 122.949849f, - 131.945283f, 133.854731f, - 130.392311f, 144.759613f, - 125.856872f, 154.797439f, - 118.699582f, 163.170096f, - 109.489523f, 169.211866f, - 98.958994f, 172.442364f, - 87.945283f, 172.604731f, - 72.507313f, 172.672927f, - 57.678920f, 168.377071f, - 44.668135f, 160.067134f, - 34.534908f, 148.420104f, - 28.104767f, 134.384831f, - 25.901557f, 119.104731f, - 28.104767f, 103.824631f, - 34.534908f, 89.789358f, - 44.668135f, 78.142327f, - 57.678920f, 69.832390f, - 72.507313f, 65.536534f, - 87.945283f, 65.604731f, - 106.918117f, 65.688542f, - 125.141795f, 60.409056f, - 141.131686f, 50.196376f, - 153.585137f, 35.882502f, - 161.487600f, 18.633545f, - 164.195283f, -0.145269f, - 161.487600f, -18.924084f, - 153.585137f, -36.173040f, - 141.131686f, -50.486914f, - 125.141795f, -60.699594f, - 106.918117f, -65.979081f, - 87.945283f, -65.895269f, - 80f, -65.895269f, - 60f, -65.895269f, - 40f, -65.895269f, - 20f, -65.895269f, - 0f, -65.895269f, - -20f, -65.895269f, - -40f, -65.895269f, - -60f, -65.895269f, - -80f, -65.895269f, - -87.945283f, -65.895269f, - -106.918117f, -65.979081f, - -125.141795f, -60.699594f, - -141.131686f, -50.486914f, - -153.585137f, -36.173040f, - -161.487600f, -18.924084f, - -164.195283f, -0.145269f, - -161.487600f, 18.633545f, - -153.585137f, 35.882502f, - -141.131686f, 50.196376f, - -125.141795f, 60.409056f, - -106.918117f, 65.688542f, - -87.945283f, 65.604731f, - -72.507313f, 65.536534f, - -57.678920f, 69.832390f, - -44.668135f, 78.142327f, - -34.534908f, 89.789358f, - -28.104767f, 103.824631f, - -25.901557f, 119.104731f, - -28.104767f, 134.384831f, - -34.534908f, 148.420104f, - -44.668135f, 160.067134f, - -57.678920f, 168.377071f, - -72.507313f, 172.672927f, - -87.945283f, 172.604731f, - -98.958994f, 172.442364f, - -109.489523f, 169.211866f, - -118.699582f, 163.170096f, - -125.856872f, 154.797439f, - -130.392311f, 144.759613f, - -131.945283f, 133.854731f, - -130.392311f, 122.949849f, - -125.856872f, 112.912022f, - -118.699582f, 104.539366f, - -109.489523f, 98.497596f, - -98.958994f, 95.267098f, - -87.945283f, 95.104731f, - -84.371773f, 95.771023f, - -80.898574f, 96.843781f, - -77.571757f, 98.308777f, - -74.435452f, 100.146577f, - -71.531259f, 102.332803f, - -68.897703f, 104.838457f, - -66.569716f, 107.630302f, - -64.578177f, 110.671304f, - -62.949505f, 113.921127f, - -61.705303f, 117.336662f, - -60.862074f, 120.872604f, - -60.431003f, 124.482050f - }; - - - mTriangleOffsets = new int[64]; - mTriangleOffsetsTex = new float[64]; - - mTriangleOffsets[0] = 0; - mTriangleOffsetsCount = 1; - - Vertex t = new Vertex(); - t.nxyz(1, 0, 0); - int count = vtx.length / 2; - - SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder( - rs, 3, - SimpleMesh.TriangleMeshBuilder.NORMAL | SimpleMesh.TriangleMeshBuilder.TEXTURE_0); - - float runningS = 0; - for (int ct=0; ct < (count-1); ct++) { - t.x = -vtx[ct*2] / 100.f; - t.z = vtx[ct*2+1] / 100.f; - t.s = runningS; - t.nx = (vtx[ct*2+3] - vtx[ct*2 +1]); - t.ny = (vtx[ct*2+2] - vtx[ct*2 ]); - float len = (float)java.lang.Math.sqrt(t.nx * t.nx + t.ny * t.ny); - runningS += len / 100; - t.nx /= len; - t.ny /= len; - t.y = -0.5f; - t.t = 0; - tm.setNormal(t.nx, t.ny, t.nz); - tm.setTexture(t.s, t.t); - tm.addVertex(t.x, t.y, t.z); - //android.util.Log.e("rs", "vtx x="+t.x+" y="+t.y+" z="+t.z+" s="+t.s+" t="+t.t); - t.y = .5f; - t.t = 1; - tm.setTexture(t.s, t.t); - tm.addVertex(t.x, t.y, t.z); - //android.util.Log.e("rs", "vtx x="+t.x+" y="+t.y+" z="+t.z+" s="+t.s+" t="+t.t); - - if((runningS*2) > mTriangleOffsetsCount) { - mTriangleOffsets[mTriangleOffsetsCount] = ct*2 * 3; - mTriangleOffsetsTex[mTriangleOffsetsCount] = t.s; - mTriangleOffsetsCount ++; - } - } - - count = (count * 2 - 2); - for (int ct=0; ct < (count-2); ct+= 2) { - tm.addTriangle(ct, ct+1, ct+2); - tm.addTriangle(ct+1, ct+3, ct+2); - } - return tm.create(); - } - - -} - diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk index f7e53a8..71944b2 100644 --- a/libs/rs/java/Fountain/Android.mk +++ b/libs/rs/java/Fountain/Android.mk @@ -14,14 +14,18 @@ # limitations under the License. # +ifneq ($(TARGET_SIMULATOR),true) + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript LOCAL_PACKAGE_NAME := Fountain include $(BUILD_PACKAGE) + +endif diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png Binary files differdeleted file mode 100755 index e91bfb4..0000000 --- a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png +++ /dev/null diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c deleted file mode 100644 index 73b819b..0000000 --- a/libs/rs/java/Fountain/res/raw/fountain.c +++ /dev/null @@ -1,52 +0,0 @@ -// Fountain test script -#pragma version(1) - -int newPart = 0; - -int main(int launchID) { - int ct; - int count = Control->count; - int rate = Control->rate; - float height = getHeight(); - struct point_s * p = (struct point_s *)point; - - if (rate) { - float rMax = ((float)rate) * 0.005f; - int x = Control->x; - int y = Control->y; - int color = ((int)(Control->r * 255.f)) | - ((int)(Control->g * 255.f)) << 8 | - ((int)(Control->b * 255.f)) << 16 | - (0xf0 << 24); - struct point_s * np = &p[newPart]; - - while (rate--) { - vec2Rand((float *)&np->delta.x, rMax); - np->position.x = x; - np->position.y = y; - np->color = color; - newPart++; - np++; - if (newPart >= count) { - newPart = 0; - np = &p[newPart]; - } - } - } - - for (ct=0; ct < count; ct++) { - float dy = p->delta.y + 0.15f; - float posy = p->position.y + dy; - if ((posy > height) && (dy > 0)) { - dy *= -0.3f; - } - p->delta.y = dy; - p->position.x += p->delta.x; - p->position.y = posy; - p++; - } - - uploadToBufferObject(NAMED_PartBuffer); - drawSimpleMesh(NAMED_PartMesh); - return 1; -} diff --git a/libs/rs/java/Fountain/res/raw/fountain2.rs b/libs/rs/java/Fountain/res/raw/fountain2.rs deleted file mode 100644 index 3301140..0000000 --- a/libs/rs/java/Fountain/res/raw/fountain2.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Fountain test script -#pragma version(1) - -#include "rs_types.rsh" -#include "rs_math.rsh" -#include "rs_graphics.rsh" - -static int newPart = 0; - -typedef struct Control_s { - int x, y; - int rate; - int count; - float r, g, b; - rs_allocation partBuffer; - rs_mesh partMesh; -} Control_t; -Control_t *Control; - -typedef struct Point_s{ - float2 delta; - float2 position; - unsigned int color; -} Point_t; -Point_t *point; - -int main(int launchID) { - int ct; - int count = Control->count; - int rate = Control->rate; - float height = getHeight(); - Point_t * p = point; - - if (rate) { - float rMax = ((float)rate) * 0.005f; - int x = Control->x; - int y = Control->y; - int color = ((int)(Control->r * 255.f)) | - ((int)(Control->g * 255.f)) << 8 | - ((int)(Control->b * 255.f)) << 16 | - (0xf0 << 24); - Point_t * np = &p[newPart]; - - while (rate--) { - np->delta = vec2Rand(rMax); - np->position.x = x; - np->position.y = y; - np->color = color; - newPart++; - np++; - if (newPart >= count) { - newPart = 0; - np = &p[newPart]; - } - } - } - - for (ct=0; ct < count; ct++) { - float dy = p->delta.y + 0.15f; - float posy = p->position.y + dy; - if ((posy > height) && (dy > 0)) { - dy *= -0.3f; - } - p->delta.y = dy; - p->position.x += p->delta.x; - p->position.y = posy; - p++; - } - - uploadToBufferObject(Control->partBuffer); - drawSimpleMesh(Control->partMesh); - return 1; -} diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java index 9356579..0b26cfd 100644 --- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java +++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java @@ -22,94 +22,50 @@ import android.util.Log; public class FountainRS { - public static final int PART_COUNT = 20000; - - static class SomeData { - public int x; - public int y; - public int rate; - public int count; - public float r; - public float g; - public float b; - } + public static final int PART_COUNT = 50000; public FountainRS() { } + private Resources mRes; + private RenderScriptGL mRS; + private ScriptC_fountain mScript; public void init(RenderScriptGL rs, Resources res, int width, int height) { mRS = rs; mRes = res; - initRS(); - } - - public void newTouchPosition(int x, int y, int rate) { - if (mSD.rate == 0) { - mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f; - mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f; - mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f; - if ((mSD.r + mSD.g + mSD.b) < 0.9f) { - mSD.r = 0.8f; - mSD.g = 0.5f; - mSD.b = 1.f; - } - } - mSD.rate = rate; - mSD.x = x; - mSD.y = y; - mIntAlloc.data(mSD); - } - - - ///////////////////////////////////////// - - private Resources mRes; - - private RenderScriptGL mRS; - private Allocation mIntAlloc; - private SimpleMesh mSM; - private SomeData mSD; - private Type mSDType; - private void initRS() { - mSD = new SomeData(); - mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData"); - mIntAlloc = Allocation.createTyped(mRS, mSDType); - mSD.count = PART_COUNT; - mIntAlloc.data(mSD); + ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs); + pfb.setVaryingColor(true); + rs.contextBindProgramFragment(pfb.create()); - Element.Builder eb = new Element.Builder(mRS); - eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "delta"); - eb.add(Element.createAttrib(mRS, Element.DataType.FLOAT_32, Element.DataKind.POSITION, 2), "position"); - eb.add(Element.createAttrib(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.COLOR, 4), "color"); - Element primElement = eb.create(); + ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT); + Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); + smb.addVertexAllocation(points.getAllocation()); + smb.addIndexType(Primitive.POINT); + Mesh sm = smb.create(); - SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS); - int vtxSlot = smb.addVertexType(primElement, PART_COUNT); - smb.setPrimitive(Primitive.POINT); - mSM = smb.create(); - mSM.setName("PartMesh"); - - Allocation partAlloc = mSM.createVertexAllocation(vtxSlot); - partAlloc.setName("PartBuffer"); - mSM.bindVertexAllocation(partAlloc, 0); + mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain, true); + mScript.set_partMesh(sm); + mScript.bind_point(points); + mRS.contextBindRootScript(mScript); + } - // All setup of named objects should be done by this point - // because we are about to compile the script. - ScriptC.Builder sb = new ScriptC.Builder(mRS); - sb.setScript(mRes, R.raw.fountain); - sb.setRoot(true); - sb.setType(mSDType, "Control", 0); - sb.setType(mSM.getVertexType(0), "point", 1); - Script script = sb.create(); - script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); + boolean holdingColor[] = new boolean[10]; + public void newTouchPosition(float x, float y, float pressure, int id) { + if (id > holdingColor.length) { + return; + } + int rate = (int)(pressure * pressure * 500.f); + if(rate > 500) { + rate = 500; + } + if (rate > 0) { + mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]); + holdingColor[id] = true; + } else { + holdingColor[id] = false; + } - script.bindAllocation(mIntAlloc, 0); - script.bindAllocation(partAlloc, 1); - mRS.contextBindRootScript(script); } - } - - diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java index dfd6a49..987bebe 100644 --- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java +++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java @@ -52,7 +52,8 @@ public class FountainView extends RSSurfaceView { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); if (mRS == null) { - mRS = createRenderScript(false); + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + mRS = createRenderScript(sc); mRS.contextSetSurface(w, h, holder.getSurface()); mRender = new FountainRS(); mRender.init(mRS, getResources(), w, h); @@ -71,17 +72,33 @@ public class FountainView extends RSSurfaceView { @Override public boolean onTouchEvent(MotionEvent ev) { - int act = ev.getAction(); + int act = ev.getActionMasked(); if (act == ev.ACTION_UP) { - mRender.newTouchPosition(0, 0, 0); + mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0)); return false; + } else if (act == MotionEvent.ACTION_POINTER_UP) { + // only one pointer going up, we can get the index like this + int pointerIndex = ev.getActionIndex(); + int pointerId = ev.getPointerId(pointerIndex); + mRender.newTouchPosition(0, 0, 0, pointerId); } - float rate = (ev.getPressure() * 50.f); - rate *= rate; - if(rate > 2000.f) { - rate = 2000.f; + int count = ev.getHistorySize(); + int pcount = ev.getPointerCount(); + + for (int p=0; p < pcount; p++) { + int id = ev.getPointerId(p); + mRender.newTouchPosition(ev.getX(p), + ev.getY(p), + ev.getPressure(p), + id); + + for (int i=0; i < count; i++) { + mRender.newTouchPosition(ev.getHistoricalX(p, i), + ev.getHistoricalY(p, i), + ev.getHistoricalPressure(p, i), + id); + } } - mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate); return true; } } diff --git a/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs new file mode 100644 index 0000000..5445744 --- /dev/null +++ b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs @@ -0,0 +1,71 @@ +// Fountain test script +#pragma version(1) + +#pragma rs java_package_name(com.android.fountain) + +#pragma stateFragment(parent) + +#include "rs_graphics.rsh" + +static int newPart = 0; +rs_mesh partMesh; + +typedef struct __attribute__((packed, aligned(4))) Point { + float2 delta; + float2 position; + uchar4 color; +} Point_t; +Point_t *point; + +#pragma rs export_func(addParticles) + +int root() { + float dt = min(rsGetDt(), 0.1f); + rsgClearColor(0.f, 0.f, 0.f, 1.f); + const float height = rsgGetHeight(); + const int size = rsAllocationGetDimX(rsGetAllocation(point)); + float dy2 = dt * (10.f); + Point_t * p = point; + for (int ct=0; ct < size; ct++) { + p->delta.y += dy2; + p->position += p->delta; + if ((p->position.y > height) && (p->delta.y > 0)) { + p->delta.y *= -0.3f; + } + p++; + } + + rsgDrawMesh(partMesh); + return 1; +} + +static float4 partColor[10]; +void addParticles(int rate, float x, float y, int index, bool newColor) +{ + if (newColor) { + partColor[index].x = rsRand(0.5f, 1.0f); + partColor[index].y = rsRand(1.0f); + partColor[index].z = rsRand(1.0f); + } + float rMax = ((float)rate) * 0.02f; + int size = rsAllocationGetDimX(rsGetAllocation(point)); + uchar4 c = rsPackColorTo8888(partColor[index]); + + Point_t * np = &point[newPart]; + float2 p = {x, y}; + while (rate--) { + float angle = rsRand(3.14f * 2.f); + float len = rsRand(rMax); + np->delta.x = len * sin(angle); + np->delta.y = len * cos(angle); + np->position = p; + np->color = c; + newPart++; + np++; + if (newPart >= size) { + newPart = 0; + np = &point[newPart]; + } + } +} + diff --git a/libs/rs/java/ImageProcessing/Android.mk b/libs/rs/java/ImageProcessing/Android.mk index 833427b..7fa30d0 100644 --- a/libs/rs/java/ImageProcessing/Android.mk +++ b/libs/rs/java/ImageProcessing/Android.mk @@ -14,14 +14,19 @@ # limitations under the License. # +ifneq ($(TARGET_SIMULATOR),true) + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + $(call all-renderscript-files-under, src) #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript LOCAL_PACKAGE_NAME := ImageProcessing include $(BUILD_PACKAGE) + +endif diff --git a/libs/rs/java/ImageProcessing/AndroidManifest.xml b/libs/rs/java/ImageProcessing/AndroidManifest.xml index b48d208..d6a2db4 100644 --- a/libs/rs/java/ImageProcessing/AndroidManifest.xml +++ b/libs/rs/java/ImageProcessing/AndroidManifest.xml @@ -6,7 +6,8 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:label="Image Processing"> - <activity android:name="ImageProcessingActivity"> + <activity android:name="ImageProcessingActivity" + android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/libs/rs/java/ImageProcessing/res/drawable/data.jpg b/libs/rs/java/ImageProcessing/res/drawable/data.jpg Binary files differnew file mode 100644 index 0000000..81a87b1 --- /dev/null +++ b/libs/rs/java/ImageProcessing/res/drawable/data.jpg diff --git a/libs/rs/java/ImageProcessing/res/layout/main.xml b/libs/rs/java/ImageProcessing/res/layout/main.xml index 6770c18..c6ec729 100644 --- a/libs/rs/java/ImageProcessing/res/layout/main.xml +++ b/libs/rs/java/ImageProcessing/res/layout/main.xml @@ -25,9 +25,147 @@ android:id="@+id/display" android:layout_width="320dip" android:layout_height="266dip" /> - + + <Button + android:layout_marginBottom="170dip" + android:layout_width="wrap_content" + android:layout_height="40dip" + android:text="@string/benchmark" + android:onClick="benchmark" + android:layout_gravity="bottom"/> + + <TextView + android:id="@+id/benchmarkText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="100dip" + android:layout_marginBottom="175dip" + android:layout_gravity="bottom" + android:text="@string/saturation"/> + + <SeekBar + android:id="@+id/inSaturation" + android:layout_marginBottom="140dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inSaturationText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="142dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/saturation"/> + + <SeekBar + android:id="@+id/inGamma" + android:layout_marginBottom="110dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inGammaText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="112dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/gamma"/> + <SeekBar - android:id="@+id/threshold" + android:id="@+id/outWhite" + android:layout_marginBottom="80dip" + android:layout_marginLeft="170dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/outWhiteText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="220dip" + android:layout_marginBottom="82dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/out_white"/> + + <SeekBar + android:id="@+id/inWhite" + android:layout_marginBottom="80dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="170dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inWhiteText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="82dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/in_white"/> + + <SeekBar + android:id="@+id/outBlack" + android:layout_marginBottom="50dip" + android:layout_marginLeft="170dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/outBlackText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="220dip" + android:layout_marginBottom="52dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/out_black"/> + + <SeekBar + android:id="@+id/inBlack" + android:layout_marginBottom="50dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="170dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inBlackText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="52dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/in_black"/> + + <SeekBar + android:id="@+id/radius" android:layout_marginBottom="10dip" android:layout_marginLeft="10dip" android:layout_marginRight="10dip" @@ -35,4 +173,15 @@ android:layout_height="wrap_content" android:layout_gravity="bottom" /> + <TextView + android:id="@+id/blurText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="12dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/blur_description"/> + </merge>
\ No newline at end of file diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs deleted file mode 100644 index 888f0cd..0000000 --- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs +++ /dev/null @@ -1,62 +0,0 @@ -/* -// block of defines matching what RS will insert at runtime. -struct Params_s{ - int inHeight; - int inWidth; - int outHeight; - int outWidth; - float threshold; -}; -struct Params_s * Params; -struct InPixel_s{ - char a; - char b; - char g; - char r; -}; -struct InPixel_s * InPixel; -struct OutPixel_s{ - char a; - char b; - char g; - char r; -}; -struct OutPixel_s * OutPixel; -*/ - -struct color_s { - char b; - char g; - char r; - char a; -}; - -void main() { - int t = uptimeMillis(); - - struct color_s *in = (struct color_s *) InPixel; - struct color_s *out = (struct color_s *) OutPixel; - - int count = Params->inWidth * Params->inHeight; - int i; - float threshold = (Params->threshold * 255.f); - - for (i = 0; i < count; i++) { - float luminance = 0.2125f * in->r + - 0.7154f * in->g + - 0.0721f * in->b; - if (luminance > threshold) { - *out = *in; - } else { - *((int *)out) = *((int *)in) & 0xff000000; - } - - in++; - out++; - } - - t= uptimeMillis() - t; - debugI32("Filter time", t); - - sendToClient(&count, 1, 4, 0); -} diff --git a/libs/rs/java/ImageProcessing/res/values/strings.xml b/libs/rs/java/ImageProcessing/res/values/strings.xml new file mode 100644 index 0000000..cc5cc4d --- /dev/null +++ b/libs/rs/java/ImageProcessing/res/values/strings.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- General --> + <skip /> + <!--slider label --> + <string name="blur_description">Blur Radius</string> + <string name="in_white">In White</string> + <string name="out_white">Out White</string> + <string name="in_black">In Black</string> + <string name="out_black">Out Black</string> + <string name="gamma">Gamma</string> + <string name="saturation">Saturation</string> + <string name="benchmark">Benchmark</string> + +</resources> diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index 9ce53d8..e806969 100644 --- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -31,53 +31,56 @@ import android.view.SurfaceView; import android.view.SurfaceHolder; import android.widget.ImageView; import android.widget.SeekBar; +import android.widget.TextView; +import android.view.View; import java.lang.Math; -public class ImageProcessingActivity extends Activity implements SurfaceHolder.Callback { - private Bitmap mBitmap; - private Params mParams; - private Script.Invokable mInvokable; - private int[] mInData; - private int[] mOutData; +public class ImageProcessingActivity extends Activity + implements SurfaceHolder.Callback, + SeekBar.OnSeekBarChangeListener { + private Bitmap mBitmapIn; + private Bitmap mBitmapOut; + private Bitmap mBitmapScratch; + private ScriptC_threshold mScript; + private ScriptC_vertical_blur mScriptVBlur; + private ScriptC_horizontal_blur mScriptHBlur; + private int mRadius = 0; + private SeekBar mRadiusSeekBar; + + private float mInBlack = 0.0f; + private SeekBar mInBlackSeekBar; + private float mOutBlack = 0.0f; + private SeekBar mOutBlackSeekBar; + private float mInWhite = 255.0f; + private SeekBar mInWhiteSeekBar; + private float mOutWhite = 255.0f; + private SeekBar mOutWhiteSeekBar; + private float mGamma = 1.0f; + private SeekBar mGammaSeekBar; + + private float mSaturation = 1.0f; + private SeekBar mSaturationSeekBar; + + private TextView mBenchmarkResult; @SuppressWarnings({"FieldCanBeLocal"}) private RenderScript mRS; @SuppressWarnings({"FieldCanBeLocal"}) - private Type mParamsType; - @SuppressWarnings({"FieldCanBeLocal"}) - private Allocation mParamsAllocation; - @SuppressWarnings({"FieldCanBeLocal"}) private Type mPixelType; @SuppressWarnings({"FieldCanBeLocal"}) private Allocation mInPixelsAllocation; @SuppressWarnings({"FieldCanBeLocal"}) private Allocation mOutPixelsAllocation; + @SuppressWarnings({"FieldCanBeLocal"}) + private Allocation mScratchPixelsAllocation1; + private Allocation mScratchPixelsAllocation2; private SurfaceView mSurfaceView; private ImageView mDisplayView; - static class Params { - public int inWidth; - public int outWidth; - public int inHeight; - public int outHeight; - - public float threshold; - } - - static class Pixel { - public byte a; - public byte r; - public byte g; - public byte b; - } - class FilterCallback extends RenderScript.RSMessage { private Runnable mAction = new Runnable() { public void run() { - mOutPixelsAllocation.readData(mOutData); - mBitmap.setPixels(mOutData, 0, mParams.outWidth, 0, 0, - mParams.outWidth, mParams.outHeight); mDisplayView.invalidate(); } }; @@ -89,29 +92,218 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C } } - private void javaFilter() { + int in[]; + int interm[]; + int out[]; + int MAX_RADIUS = 25; + // Store our coefficients here + float gaussian[]; + + private long javaFilter() { + final int width = mBitmapIn.getWidth(); + final int height = mBitmapIn.getHeight(); + final int count = width * height; + + if (in == null) { + in = new int[count]; + interm = new int[count]; + out = new int[count]; + gaussian = new float[MAX_RADIUS * 2 + 1]; + mBitmapIn.getPixels(in, 0, width, 0, 0, width, height); + } + long t = java.lang.System.currentTimeMillis(); - int count = mParams.inWidth * mParams.inHeight; - float threshold = mParams.threshold * 255.f; - - for (int i = 0; i < count; i++) { - final float r = (float)((mInData[i] >> 0) & 0xff); - final float g = (float)((mInData[i] >> 8) & 0xff); - final float b = (float)((mInData[i] >> 16) & 0xff); - - final float luminance = 0.2125f * r + - 0.7154f * g + - 0.0721f * b; - if (luminance > threshold) { - mOutData[i] = mInData[i]; - } else { - mOutData[i] = mInData[i] & 0xff000000; + + int w, h, r; + + float fRadius = (float)mRadius; + int radius = (int)mRadius; + + // Compute gaussian weights for the blur + // e is the euler's number + float e = 2.718281828459045f; + float pi = 3.1415926535897932f; + // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) + // x is of the form [-radius .. 0 .. radius] + // and sigma varies with radius. + // Based on some experimental radius values and sigma's + // we approximately fit sigma = f(radius) as + // sigma = radius * 0.4 + 0.6 + // The larger the radius gets, the more our gaussian blur + // will resemble a box blur since with large sigma + // the gaussian curve begins to lose its shape + float sigma = 0.4f * fRadius + 0.6f; + // Now compute the coefficints + // We will store some redundant values to save some math during + // the blur calculations + // precompute some values + float coeff1 = 1.0f / (float)(Math.sqrt( 2.0f * pi ) * sigma); + float coeff2 = - 1.0f / (2.0f * sigma * sigma); + float normalizeFactor = 0.0f; + float floatR = 0.0f; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] = coeff1 * (float)Math.pow(e, floatR * floatR * coeff2); + normalizeFactor += gaussian[r + radius]; + } + + //Now we need to normalize the weights because all our coefficients need to add up to one + normalizeFactor = 1.0f / normalizeFactor; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] *= normalizeFactor; + } + + float blurredPixelR = 0.0f; + float blurredPixelG = 0.0f; + float blurredPixelB = 0.0f; + float blurredPixelA = 0.0f; + + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixelR = 0.0f; + blurredPixelG = 0.0f; + blurredPixelB = 0.0f; + blurredPixelA = 0.0f; + + for(r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validW = w + r; + // Clamp to zero and width max() isn't exposed for ints yet + if(validW < 0) { + validW = 0; + } + if(validW > width - 1) { + validW = width - 1; + } + + int input = in[h*width + validW]; + + int R = ((input >> 24) & 0xff); + int G = ((input >> 16) & 0xff); + int B = ((input >> 8) & 0xff); + int A = (input & 0xff); + + float weight = gaussian[r + radius]; + + blurredPixelR += (float)(R)*weight; + blurredPixelG += (float)(G)*weight; + blurredPixelB += (float)(B)*weight; + blurredPixelA += (float)(A)*weight; + } + + int R = (int)blurredPixelR; + int G = (int)blurredPixelG; + int B = (int)blurredPixelB; + int A = (int)blurredPixelA; + + interm[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); + } + } + + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixelR = 0.0f; + blurredPixelG = 0.0f; + blurredPixelB = 0.0f; + blurredPixelA = 0.0f; + for(r = -radius; r <= radius; r ++) { + int validH = h + r; + // Clamp to zero and width + if(validH < 0) { + validH = 0; + } + if(validH > height - 1) { + validH = height - 1; + } + + int input = interm[validH*width + w]; + + int R = ((input >> 24) & 0xff); + int G = ((input >> 16) & 0xff); + int B = ((input >> 8) & 0xff); + int A = (input & 0xff); + + float weight = gaussian[r + radius]; + + blurredPixelR += (float)(R)*weight; + blurredPixelG += (float)(G)*weight; + blurredPixelB += (float)(B)*weight; + blurredPixelA += (float)(A)*weight; + } + + int R = (int)blurredPixelR; + int G = (int)blurredPixelG; + int B = (int)blurredPixelB; + int A = (int)blurredPixelA; + + out[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); } } t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Java frame time ms " + t); + mBitmapOut.setPixels(out, 0, width, 0, 0, width, height); + return t; + } + + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { - android.util.Log.v("Img", "frame time ms " + t); + if(seekBar == mRadiusSeekBar) { + float fRadius = progress / 100.0f; + fRadius *= (float)(MAX_RADIUS); + mRadius = (int)fRadius; + + mScript.set_radius(mRadius); + } + else if(seekBar == mInBlackSeekBar) { + mInBlack = (float)progress; + mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite); + } + else if(seekBar == mOutBlackSeekBar) { + mOutBlack = (float)progress; + mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite); + } + else if(seekBar == mInWhiteSeekBar) { + mInWhite = (float)progress + 127.0f; + mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite); + } + else if(seekBar == mOutWhiteSeekBar) { + mOutWhite = (float)progress + 127.0f; + mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite); + } + else if(seekBar == mGammaSeekBar) { + mGamma = (float)progress/100.0f; + mGamma = Math.max(mGamma, 0.1f); + mGamma = 1.0f / mGamma; + mScriptVBlur.invoke_setGamma(mGamma); + } + else if(seekBar == mSaturationSeekBar) { + mSaturation = (float)progress / 50.0f; + mScriptVBlur.invoke_setSaturation(mSaturation); + } + + long t = java.lang.System.currentTimeMillis(); + if (true) { + mScript.invoke_filter(); + mRS.finish(); + } else { + javaFilter(); + mDisplayView.invalidate(); + } + + t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Renderscript frame time core ms " + t); + } + } + + public void onStartTrackingTouch(SeekBar seekBar) { + } + + public void onStopTrackingTouch(SeekBar seekBar) { } @Override @@ -119,45 +311,54 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C super.onCreate(savedInstanceState); setContentView(R.layout.main); - mBitmap = loadBitmap(R.drawable.data); + mBitmapIn = loadBitmap(R.drawable.data); + mBitmapOut = loadBitmap(R.drawable.data); + mBitmapScratch = loadBitmap(R.drawable.data); mSurfaceView = (SurfaceView) findViewById(R.id.surface); mSurfaceView.getHolder().addCallback(this); mDisplayView = (ImageView) findViewById(R.id.display); - mDisplayView.setImageBitmap(mBitmap); - - ((SeekBar) findViewById(R.id.threshold)).setOnSeekBarChangeListener( - new SeekBar.OnSeekBarChangeListener() { - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - mParams.threshold = progress / 100.0f; - mParamsAllocation.data(mParams); - - if (true) { - mInvokable.execute(); - } else { - javaFilter(); - mBitmap.setPixels(mOutData, 0, mParams.outWidth, 0, 0, - mParams.outWidth, mParams.outHeight); - mDisplayView.invalidate(); - } - } - } - - public void onStartTrackingTouch(SeekBar seekBar) { - } - - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); + mDisplayView.setImageBitmap(mBitmapOut); + + mRadiusSeekBar = (SeekBar) findViewById(R.id.radius); + mRadiusSeekBar.setOnSeekBarChangeListener(this); + + mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack); + mInBlackSeekBar.setOnSeekBarChangeListener(this); + mInBlackSeekBar.setMax(128); + mInBlackSeekBar.setProgress(0); + mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack); + mOutBlackSeekBar.setOnSeekBarChangeListener(this); + mOutBlackSeekBar.setMax(128); + mOutBlackSeekBar.setProgress(0); + + mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite); + mInWhiteSeekBar.setOnSeekBarChangeListener(this); + mInWhiteSeekBar.setMax(128); + mInWhiteSeekBar.setProgress(128); + mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite); + mOutWhiteSeekBar.setOnSeekBarChangeListener(this); + mOutWhiteSeekBar.setMax(128); + mOutWhiteSeekBar.setProgress(128); + + mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma); + mGammaSeekBar.setOnSeekBarChangeListener(this); + mGammaSeekBar.setMax(150); + mGammaSeekBar.setProgress(100); + + mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation); + mSaturationSeekBar.setOnSeekBarChangeListener(this); + mSaturationSeekBar.setProgress(50); + + mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText); + mBenchmarkResult.setText("Benchmark not yet run"); } public void surfaceCreated(SurfaceHolder holder) { - mParams = createParams(); - mInvokable = createScript(); - - mInvokable.execute(); + createScript(); + mScript.invoke_filter(); + mRS.finish(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { @@ -166,54 +367,38 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C public void surfaceDestroyed(SurfaceHolder holder) { } - private Script.Invokable createScript() { + private void createScript() { mRS = RenderScript.create(); mRS.mMessageCallback = new FilterCallback(); - mParamsType = Type.createFromClass(mRS, Params.class, 1, "Parameters"); - mParamsAllocation = Allocation.createTyped(mRS, mParamsType); - mParamsAllocation.data(mParams); - - final int pixelCount = mParams.inWidth * mParams.inHeight; - - mPixelType = Type.createFromClass(mRS, Pixel.class, 1, "Pixel"); - mInPixelsAllocation = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.SIGNED_32), - pixelCount); - mOutPixelsAllocation = Allocation.createSized(mRS, - Element.createUser(mRS, Element.DataType.SIGNED_32), - pixelCount); - - mInData = new int[pixelCount]; - mBitmap.getPixels(mInData, 0, mParams.inWidth, 0, 0, mParams.inWidth, mParams.inHeight); - mInPixelsAllocation.data(mInData); - - mOutData = new int[pixelCount]; - mOutPixelsAllocation.data(mOutData); - - ScriptC.Builder sb = new ScriptC.Builder(mRS); - sb.setType(mParamsType, "Params", 0); - sb.setType(mPixelType, "InPixel", 1); - sb.setType(mPixelType, "OutPixel", 2); - sb.setType(true, 2); - Script.Invokable invokable = sb.addInvokable("main"); - sb.setScript(getResources(), R.raw.threshold); - //sb.setRoot(true); - - ScriptC script = sb.create(); - script.bindAllocation(mParamsAllocation, 0); - script.bindAllocation(mInPixelsAllocation, 1); - script.bindAllocation(mOutPixelsAllocation, 2); - - return invokable; - } + mInPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapIn); + mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut); + + Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS)); + tb.add(android.renderscript.Dimension.X, mBitmapIn.getWidth()); + tb.add(android.renderscript.Dimension.Y, mBitmapIn.getHeight()); + mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create()); + mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create()); + + mScriptVBlur = new ScriptC_vertical_blur(mRS, getResources(), R.raw.vertical_blur, false); + mScriptHBlur = new ScriptC_horizontal_blur(mRS, getResources(), R.raw.horizontal_blur, false); + + mScript = new ScriptC_threshold(mRS, getResources(), R.raw.threshold, false); + mScript.set_width(mBitmapIn.getWidth()); + mScript.set_height(mBitmapIn.getHeight()); + mScript.set_radius(mRadius); + + mScriptVBlur.invoke_setLevels(mInBlack, mOutBlack, mInWhite, mOutWhite); + mScriptVBlur.invoke_setGamma(mGamma); + mScriptVBlur.invoke_setSaturation(mSaturation); + + mScript.bind_InPixel(mInPixelsAllocation); + mScript.bind_OutPixel(mOutPixelsAllocation); + mScript.bind_ScratchPixel1(mScratchPixelsAllocation1); + mScript.bind_ScratchPixel2(mScratchPixelsAllocation2); - private Params createParams() { - final Params params = new Params(); - params.inWidth = params.outWidth = mBitmap.getWidth(); - params.inHeight = params.outHeight = mBitmap.getHeight(); - params.threshold = 0.5f; - return params; + mScript.set_vBlurScript(mScriptVBlur); + mScript.set_hBlurScript(mScriptHBlur); } private Bitmap loadBitmap(int resource) { @@ -229,4 +414,30 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C source.recycle(); return b; } + + // button hook + public void benchmark(View v) { + android.util.Log.v("Img", "Benchmarking"); + int oldRadius = mRadius; + mRadius = MAX_RADIUS; + mScript.set_radius(mRadius); + + long t = java.lang.System.currentTimeMillis(); + + mScript.invoke_filter(); + mRS.finish(); + + t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Renderscript frame time core ms " + t); + + //long javaTime = javaFilter(); + //mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms"); + mBenchmarkResult.setText("RS: " + t + " ms"); + + mRadius = oldRadius; + mScript.set_radius(mRadius); + + mScript.invoke_filter(); + mRS.finish(); + } } diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs new file mode 100644 index 0000000..cfffac8 --- /dev/null +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/horizontal_blur.rs @@ -0,0 +1,30 @@ +#pragma version(1) + +#include "ip.rsh" + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + float4 *output = (float4 *)v_out; + const FilterStruct *fs = (const FilterStruct *)usrData; + const float4 *input = (const float4 *)rsGetElementAt(fs->ain, 0, y); + + float3 blurredPixel = 0; + const float *gPtr = fs->gaussian; + if ((x > fs->radius) && (x < (fs->width - fs->radius))) { + const float4 *i = input + (x - fs->radius); + for(int r = -fs->radius; r <= fs->radius; r ++) { + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + i++; + } + } else { + for(int r = -fs->radius; r <= fs->radius; r ++) { + // Stepping left and right away from the pixel + int validW = rsClamp(x + r, (uint)0, (uint)(fs->width - 1)); + blurredPixel += input[validW].xyz * gPtr[0]; + gPtr++; + } + } + + output->xyz = blurredPixel; +} + diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh new file mode 100644 index 0000000..1d7a719 --- /dev/null +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ip.rsh @@ -0,0 +1,15 @@ +#pragma rs java_package_name(com.android.rs.image) + +#define MAX_RADIUS 25 + +typedef struct FilterStruct_s { + rs_allocation ain; + + float *gaussian; //[MAX_RADIUS * 2 + 1]; + int height; + int width; + int radius; + +} FilterStruct; + + diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs new file mode 100644 index 0000000..4f46810 --- /dev/null +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs @@ -0,0 +1,94 @@ +#pragma version(1) + +#include "ip.rsh" + +int height; +int width; +int radius; + +uchar4 * InPixel; +uchar4 * OutPixel; +float4 * ScratchPixel1; +float4 * ScratchPixel2; + +#pragma rs export_func(filter); + +rs_script vBlurScript; +rs_script hBlurScript; + +const int CMD_FINISHED = 1; + +// Store our coefficients here +static float gaussian[MAX_RADIUS * 2 + 1]; + + +static void computeGaussianWeights() { + // Compute gaussian weights for the blur + // e is the euler's number + float e = 2.718281828459045f; + float pi = 3.1415926535897932f; + // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) + // x is of the form [-radius .. 0 .. radius] + // and sigma varies with radius. + // Based on some experimental radius values and sigma's + // we approximately fit sigma = f(radius) as + // sigma = radius * 0.4 + 0.6 + // The larger the radius gets, the more our gaussian blur + // will resemble a box blur since with large sigma + // the gaussian curve begins to lose its shape + float sigma = 0.4f * (float)radius + 0.6f; + + // Now compute the coefficints + // We will store some redundant values to save some math during + // the blur calculations + // precompute some values + float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); + float coeff2 = - 1.0f / (2.0f * sigma * sigma); + + float normalizeFactor = 0.0f; + float floatR = 0.0f; + int r; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); + normalizeFactor += gaussian[r + radius]; + } + + //Now we need to normalize the weights because all our coefficients need to add up to one + normalizeFactor = 1.0f / normalizeFactor; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] *= normalizeFactor; + } +} + + +static void copyInput() { + rs_allocation ain = rsGetAllocation(InPixel); + uint32_t dimx = rsAllocationGetDimX(ain); + uint32_t dimy = rsAllocationGetDimY(ain); + for(uint32_t y = 0; y < dimy; y++) { + for(uint32_t x = 0; x < dimx; x++) { + ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]); + } + } +} + +void filter() { + copyInput(); + computeGaussianWeights(); + + FilterStruct fs; + fs.gaussian = gaussian; + fs.width = width; + fs.height = height; + fs.radius = radius; + + fs.ain = rsGetAllocation(ScratchPixel1); + rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel2), &fs); + + fs.ain = rsGetAllocation(ScratchPixel2); + rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs); + rsSendToClientBlocking(CMD_FINISHED); +} + diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs new file mode 100644 index 0000000..d901d2a --- /dev/null +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs @@ -0,0 +1,92 @@ +#pragma version(1) + +#include "ip.rsh" + +static float inBlack; +static float outBlack; +static float inWhite; +static float outWhite; +static float3 gamma; +static float saturation; + +static float inWMinInB; +static float outWMinOutB; +static float overInWMinInB; +static rs_matrix3x3 colorMat; + +#pragma rs export_func(setLevels, setSaturation, setGamma); + +void setLevels(float iBlk, float oBlk, float iWht, float oWht) { + inBlack = iBlk; + outBlack = oBlk; + inWhite = iWht; + outWhite = oWht; + + inWMinInB = inWhite - inBlack; + outWMinOutB = outWhite - outBlack; + overInWMinInB = 1.f / inWMinInB; +} + +void setSaturation(float sat) { + saturation = sat; + + // Saturation + // Linear weights + //float rWeight = 0.3086f; + //float gWeight = 0.6094f; + //float bWeight = 0.0820f; + + // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons) + float rWeight = 0.299f; + float gWeight = 0.587f; + float bWeight = 0.114f; + + float oneMinusS = 1.0f - saturation; + rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation); + rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight); + rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight); + rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight); + rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation); + rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight); + rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight); + rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight); + rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation); +} + +void setGamma(float g) { + gamma = (float3)g; +} + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + uchar4 *output = (uchar4 *)v_out; + const FilterStruct *fs = (const FilterStruct *)usrData; + const float4 *input = (const float4 *)rsGetElementAt(fs->ain, x, 0); + + float3 blurredPixel = 0; + const float *gPtr = fs->gaussian; + if ((y > fs->radius) && (y < (fs->height - fs->radius))) { + const float4 *i = input + ((y - fs->radius) * fs->width); + for(int r = -fs->radius; r <= fs->radius; r ++) { + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + i += fs->width; + } + } else { + for(int r = -fs->radius; r <= fs->radius; r ++) { + int validH = rsClamp(y + r, (uint)0, (uint)(fs->height - 1)); + const float4 *i = input + validH * fs->width; + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + } + } + + float3 temp = rsMatrixMultiply(&colorMat, blurredPixel); + temp = (clamp(temp, 0.f, 255.f) - inBlack) * overInWMinInB; + if (gamma.x != 1.0f) + temp = pow(temp, (float3)gamma); + temp = clamp(temp * outWMinOutB + outBlack, 0.f, 255.f); + + output->xyz = convert_uchar3(temp); + //output->w = input->w; +} + diff --git a/libs/rs/java/ModelViewer/Android.mk b/libs/rs/java/ModelViewer/Android.mk new file mode 100644 index 0000000..efe77d7 --- /dev/null +++ b/libs/rs/java/ModelViewer/Android.mk @@ -0,0 +1,31 @@ +# +# Copyright (C) 2008 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. +# + +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) +#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript + +LOCAL_PACKAGE_NAME := ModelViewer + +include $(BUILD_PACKAGE) + +endif diff --git a/libs/rs/java/ModelViewer/AndroidManifest.xml b/libs/rs/java/ModelViewer/AndroidManifest.xml new file mode 100644 index 0000000..959fe53 --- /dev/null +++ b/libs/rs/java/ModelViewer/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.modelviewer"> + <application android:label="ModelViewer"> + <activity android:name="SimpleModel" + android:label="SimpleModel" + android:screenOrientation="portrait" + android:theme="@android:style/Theme.Black.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name="SceneGraph" + android:label="SceneGraph" + android:theme="@android:style/Theme.Black.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/libs/rs/java/ModelViewer/res/drawable/robot.png b/libs/rs/java/ModelViewer/res/drawable/robot.png Binary files differnew file mode 100644 index 0000000..f7353fd --- /dev/null +++ b/libs/rs/java/ModelViewer/res/drawable/robot.png diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d Binary files differnew file mode 100644 index 0000000..f48895c --- /dev/null +++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java new file mode 100644 index 0000000..557e0cc --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraph.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; + +import java.lang.Runtime; + +public class SceneGraph extends Activity { + + private SceneGraphView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new SceneGraphView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mView.onResume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mView.onPause(); + } + +} + diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java new file mode 100644 index 0000000..81bd578 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import java.io.Writer; +import java.util.Map; +import java.util.Vector; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Element.Builder; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; + + +public class SceneGraphRS { + + private final int STATE_LAST_FOCUS = 1; + + int mWidth; + int mHeight; + int mRotation; + + public SceneGraphRS() { + } + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + mRotation = 0; + initRS(); + } + + private Resources mRes; + private RenderScriptGL mRS; + private Sampler mSampler; + private ProgramStore mPSBackground; + private ProgramFragment mPFBackground; + private ProgramVertex mPVBackground; + private ProgramVertex.MatrixAllocation mPVA; + + private Allocation mGridImage; + private Allocation mAllocPV; + + private Mesh mMesh; + + private Font mItalic; + private Allocation mTextAlloc; + + private ScriptC_scenegraph mScript; + private ScriptC_transform mTransformScript; + + int mLastX; + int mLastY; + + public void touchEvent(int x, int y) { + int dx = mLastX - x; + if(Math.abs(dx) > 50 || Math.abs(dx) < 3) { + dx = 0; + } + + mRotation -= dx; + if(mRotation > 360) { + mRotation -= 360; + } + if(mRotation < 0) { + mRotation += 360; + } + + mScript.set_gRotate(-(float)mRotation); + + mLastX = x; + mLastY = y; + } + + private void initPFS() { + ProgramStore.Builder b = new ProgramStore.Builder(mRS); + + b.setDepthFunc(ProgramStore.DepthFunc.LESS); + b.setDitherEnable(false); + b.setDepthMask(true); + mPSBackground = b.create(); + + mScript.set_gPFSBackground(mPSBackground); + } + + private void initPF() { + Sampler.Builder bs = new Sampler.Builder(mRS); + bs.setMin(Sampler.Value.LINEAR); + bs.setMag(Sampler.Value.LINEAR); + bs.setWrapS(Sampler.Value.CLAMP); + bs.setWrapT(Sampler.Value.CLAMP); + mSampler = bs.create(); + + ProgramFragment.Builder b = new ProgramFragment.Builder(mRS); + b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, + ProgramFragment.Builder.Format.RGBA, 0); + mPFBackground = b.create(); + mPFBackground.bindSampler(mSampler, 0); + + mScript.set_gPFBackground(mPFBackground); + } + + private void initPV() { + ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + mPVBackground = pvb.create(); + + mPVA = new ProgramVertex.MatrixAllocation(mRS); + mPVBackground.bindAllocation(mPVA); + + mScript.set_gPVBackground(mPVBackground); + } + + private void loadImage() { + mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true); + mGridImage.uploadToTexture(0); + + mScript.set_gTGrid(mGridImage); + } + + private void initTextAllocation() { + String allocString = "Displaying file: R.raw.robot"; + mTextAlloc = Allocation.createFromString(mRS, allocString); + mScript.set_gTextAlloc(mTextAlloc); + } + + SgTransform mRootTransform; + SgTransform mGroup1; + + SgTransform mRobot1; + SgTransform mRobot2; + + void initTransformHierarchy() { + mRootTransform = new SgTransform(mRS); + + mGroup1 = new SgTransform(mRS); + mRootTransform.addChild(mGroup1); + + mRobot1 = new SgTransform(mRS); + mRobot2 = new SgTransform(mRS); + + mGroup1.addChild(mRobot1); + mGroup1.addChild(mRobot2); + + mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE); + mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE); + + mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE); + mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE); + mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE); + + mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE); + mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE); + mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE); + } + + private void initRS() { + + mScript = new ScriptC_scenegraph(mRS, mRes, R.raw.scenegraph, true); + mTransformScript = new ScriptC_transform(mRS, mRes, R.raw.transform, false); + mTransformScript.set_transformScript(mTransformScript); + + mScript.set_gTransformRS(mTransformScript); + + initPFS(); + initPF(); + initPV(); + + loadImage(); + + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); + FileA3D.IndexEntry entry = model.getIndexEntry(0); + if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + Log.e("rs", "could not load model"); + } + else { + mMesh = (Mesh)entry.getObject(); + mScript.set_gTestMesh(mMesh); + } + + mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8); + mScript.set_gItalic(mItalic); + + initTextAllocation(); + + initTransformHierarchy(); + + Log.v("========SceneGraph========", "transform hierarchy initialized"); + + mScript.bind_gRootNode(mRootTransform.getField()); + + mScript.bind_gGroup(mGroup1.mParent.mChildField); + mScript.bind_gRobot1(mRobot1.mParent.mChildField); + mScript.set_gRobot1Index(mRobot1.mIndexInParentGroup); + mScript.bind_gRobot2(mRobot2.mParent.mChildField); + mScript.set_gRobot2Index(mRobot2.mIndexInParentGroup); + + mRS.contextBindRootScript(mScript); + } +} + + + diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java index 5bc2811..9457fd7 100644 --- a/libs/rs/java/Film/src/com/android/film/FilmView.java +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.film; +package com.android.modelviewer; import java.io.Writer; import java.util.ArrayList; @@ -39,23 +39,25 @@ import android.view.SurfaceView; import android.view.KeyEvent; import android.view.MotionEvent; -public class FilmView extends RSSurfaceView { +public class SceneGraphView extends RSSurfaceView { - public FilmView(Context context) { + public SceneGraphView(Context context) { super(context); //setFocusable(true); } private RenderScriptGL mRS; - private FilmRS mRender; + private SceneGraphRS mRender; public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { super.surfaceChanged(holder, format, w, h); if (mRS == null) { - mRS = createRenderScript(true); + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScript(sc); mRS.contextSetSurface(w, h, holder.getSurface()); - mRender = new FilmRS(); + mRender = new SceneGraphRS(); mRender.init(mRS, getResources(), w, h); } } @@ -85,7 +87,8 @@ public class FilmView extends RSSurfaceView { if (act == ev.ACTION_UP) { ret = false; } - mRender.setFilmStripPosition((int)ev.getX(), (int)ev.getY() / 5); + + mRender.touchEvent((int)ev.getX(), (int)ev.getY()); return ret; } } diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java new file mode 100644 index 0000000..8351f42 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SgTransform.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import java.io.Writer; +import java.util.Map; +import java.util.Vector; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Element.Builder; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; + +enum TransformType { + + NONE(0), + TRANSLATE(1), + ROTATE(2), + SCALE(3); + + int mID; + TransformType(int id) { + mID = id; + } +} + +public class SgTransform { + + + ScriptField_SgTransform mTransformField; + ScriptField_SgTransform mChildField; + public ScriptField_SgTransform.Item mTransformData; + + RenderScript mRS; + + Vector mChildren; + SgTransform mParent; + int mIndexInParentGroup; + + public void setParent(SgTransform parent, int parentIndex) { + mParent = parent; + mIndexInParentGroup = parentIndex; + } + + public void addChild(SgTransform child) { + mChildren.add(child); + child.setParent(this, mChildren.size() - 1); + } + + public void setTransform(int index, Float4 value, TransformType type) { + mTransformData.transforms[index] = value; + mTransformData.transformTypes[index] = type.mID; + } + + void initData() { + int numElements = mTransformData.transforms.length; + mTransformData.transformTypes = new int[numElements]; + for(int i = 0; i < numElements; i ++) { + mTransformData.transforms[i] = new Float4(0, 0, 0, 0); + mTransformData.transformTypes[i] = TransformType.NONE.mID; + } + + mTransformData.isDirty = 1; + mTransformData.children = null; + } + + public SgTransform(RenderScript rs) { + mRS = rs; + mTransformData = new ScriptField_SgTransform.Item(); + mChildren = new Vector(); + initData(); + } + + public ScriptField_SgTransform.Item getData() { + if(mChildren.size() != 0) { + mChildField = new ScriptField_SgTransform(mRS, mChildren.size()); + mTransformData.children = mChildField.getAllocation(); + + for(int i = 0; i < mChildren.size(); i ++) { + SgTransform child = (SgTransform)mChildren.get(i); + mChildField.set(child.getData(), i, false); + } + mChildField.copyAll(); + } + + return mTransformData; + } + + public ScriptField_SgTransform getField() { + mTransformField = new ScriptField_SgTransform(mRS, 1); + mTransformField.set(getData(), 0, true); + return mTransformField; + } +} + + + diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModel.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModel.java new file mode 100644 index 0000000..cb7c39c --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModel.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; + +import java.lang.Runtime; + +public class SimpleModel extends Activity { + + private SimpleModelView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new SimpleModelView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mView.onResume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mView.onPause(); + } + +} + diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java new file mode 100644 index 0000000..ccbecd8 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import java.io.Writer; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; + + +public class SimpleModelRS { + + private final int STATE_LAST_FOCUS = 1; + + int mWidth; + int mHeight; + int mRotation; + + public SimpleModelRS() { + } + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + mRotation = 0; + initRS(); + } + + private Resources mRes; + private RenderScriptGL mRS; + private Sampler mSampler; + private ProgramStore mPSBackground; + private ProgramFragment mPFBackground; + private ProgramVertex mPVBackground; + private ProgramVertex.MatrixAllocation mPVA; + + private Allocation mGridImage; + private Allocation mAllocPV; + + private Mesh mMesh; + + private Font mItalic; + private Allocation mTextAlloc; + + private ScriptC_simplemodel mScript; + + int mLastX; + int mLastY; + + public void touchEvent(int x, int y) { + int dx = mLastX - x; + if(Math.abs(dx) > 50 || Math.abs(dx) < 3) { + dx = 0; + } + + mRotation -= dx; + if(mRotation > 360) { + mRotation -= 360; + } + if(mRotation < 0) { + mRotation += 360; + } + + mScript.set_gRotate((float)mRotation); + + mLastX = x; + mLastY = y; + } + + private void initPFS() { + ProgramStore.Builder b = new ProgramStore.Builder(mRS); + + b.setDepthFunc(ProgramStore.DepthFunc.LESS); + b.setDitherEnable(false); + b.setDepthMask(true); + mPSBackground = b.create(); + + mScript.set_gPFSBackground(mPSBackground); + } + + private void initPF() { + Sampler.Builder bs = new Sampler.Builder(mRS); + bs.setMin(Sampler.Value.LINEAR); + bs.setMag(Sampler.Value.LINEAR); + bs.setWrapS(Sampler.Value.CLAMP); + bs.setWrapT(Sampler.Value.CLAMP); + mSampler = bs.create(); + + ProgramFragment.Builder b = new ProgramFragment.Builder(mRS); + b.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, + ProgramFragment.Builder.Format.RGBA, 0); + mPFBackground = b.create(); + mPFBackground.bindSampler(mSampler, 0); + + mScript.set_gPFBackground(mPFBackground); + } + + private void initPV() { + ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + mPVBackground = pvb.create(); + + mPVA = new ProgramVertex.MatrixAllocation(mRS); + mPVBackground.bindAllocation(mPVA); + + mScript.set_gPVBackground(mPVBackground); + } + + private void loadImage() { + mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true); + mGridImage.uploadToTexture(0); + + mScript.set_gTGrid(mGridImage); + } + + private void initTextAllocation() { + String allocString = "Displaying file: R.raw.robot"; + mTextAlloc = Allocation.createFromString(mRS, allocString); + mScript.set_gTextAlloc(mTextAlloc); + } + + private void initRS() { + + mScript = new ScriptC_simplemodel(mRS, mRes, R.raw.simplemodel, true); + + initPFS(); + initPF(); + initPV(); + + loadImage(); + + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); + FileA3D.IndexEntry entry = model.getIndexEntry(0); + if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + Log.e("rs", "could not load model"); + } + else { + mMesh = (Mesh)entry.getObject(); + mScript.set_gTestMesh(mMesh); + } + + mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8); + mScript.set_gItalic(mItalic); + + initTextAllocation(); + + mRS.contextBindRootScript(mScript); + } +} + + + diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java new file mode 100644 index 0000000..4253085 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.modelviewer; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.KeyEvent; +import android.view.MotionEvent; + +public class SimpleModelView extends RSSurfaceView { + + public SimpleModelView(Context context) { + super(context); + //setFocusable(true); + } + + private RenderScriptGL mRS; + private SimpleModelRS mRender; + + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScript(sc); + mRS.contextSetSurface(w, h, holder.getSurface()); + mRender = new SimpleModelRS(); + mRender.init(mRS, getResources(), w, h); + } + } + + @Override + protected void onDetachedFromWindow() { + if(mRS != null) { + mRS = null; + destroyRenderScript(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + // break point at here + // this method doesn't work when 'extends View' include 'extends ScrollView'. + return super.onKeyDown(keyCode, event); + } + + + @Override + public boolean onTouchEvent(MotionEvent ev) + { + boolean ret = true; + int act = ev.getAction(); + if (act == ev.ACTION_UP) { + ret = false; + } + + mRender.touchEvent((int)ev.getX(), (int)ev.getY()); + return ret; + } +} + + diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs new file mode 100644 index 0000000..3bee8d6 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs @@ -0,0 +1,91 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.modelviewer) + +#include "rs_graphics.rsh" +#include "transform_def.rsh" + +rs_program_vertex gPVBackground; +rs_program_fragment gPFBackground; + +rs_allocation gTGrid; +rs_mesh gTestMesh; + +rs_program_store gPFSBackground; + +float gRotate; + +rs_font gItalic; +rs_allocation gTextAlloc; + +rs_script gTransformRS; + +SgTransform *gGroup; +SgTransform *gRobot1; +int gRobot1Index; +SgTransform *gRobot2; +int gRobot2Index; + +SgTransform *gRootNode; + +void init() { + gRotate = 0.0f; +} + +int root(int launchID) { + + gGroup->transforms[1].w += 0.5f; + gGroup->isDirty = 1; + + SgTransform *robot1Ptr = gRobot1 + gRobot1Index; + + robot1Ptr->transforms[1].w -= 1.5f; + robot1Ptr->isDirty = 1; + + SgTransform *robot2Ptr = gRobot2 + gRobot2Index; + robot2Ptr->transforms[1].w += 2.5f; + robot2Ptr->isDirty = 1; + + rsForEach(gTransformRS, gRootNode->children, gRootNode->children, 0); + + rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgClearDepth(1.0f); + + rsgBindProgramVertex(gPVBackground); + rs_matrix4x4 proj; + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rsgBindProgramFragment(gPFBackground); + rsgBindProgramStore(gPFSBackground); + rsgBindTexture(gPFBackground, 0, gTGrid); + + rsgProgramVertexLoadModelMatrix(&robot1Ptr->globalMat); + rsgDrawMesh(gTestMesh); + + rsgProgramVertexLoadModelMatrix(&robot2Ptr->globalMat); + rsgDrawMesh(gTestMesh); + + color(0.3f, 0.3f, 0.3f, 1.0f); + rsgDrawText("Renderscript transform test", 30, 695); + + rsgBindFont(gItalic); + rsgDrawText(gTextAlloc, 30, 730); + + return 10; +} diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs new file mode 100644 index 0000000..419de62 --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs @@ -0,0 +1,71 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.modelviewer) + +#include "rs_graphics.rsh" + +rs_program_vertex gPVBackground; +rs_program_fragment gPFBackground; + +rs_allocation gTGrid; +rs_mesh gTestMesh; + +rs_program_store gPFSBackground; + +float gRotate; + +rs_font gItalic; +rs_allocation gTextAlloc; + +void init() { + gRotate = 0.0f; +} + +int root(int launchID) { + + rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgClearDepth(1.0f); + + rsgBindProgramVertex(gPVBackground); + rs_matrix4x4 proj; + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rsgBindProgramFragment(gPFBackground); + rsgBindProgramStore(gPFSBackground); + rsgBindTexture(gPFBackground, 0, gTGrid); + + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + // Position our model on the screen + rsMatrixTranslate(&matrix, 0.0f, -0.3f, -10.0f); + rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f); + rsMatrixRotate(&matrix, 25.0f, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + + rsgDrawMesh(gTestMesh); + + rsgFontColor(0.3f, 0.3f, 0.3f, 1.0f); + rsgDrawText("Renderscript model test", 30, 695); + + rsgBindFont(gItalic); + rsgDrawText(gTextAlloc, 30, 730); + + return 10; +} diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs new file mode 100644 index 0000000..e7c04de --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs @@ -0,0 +1,97 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.modelviewer) + +#include "transform_def.rsh" + +rs_script transformScript; + +typedef struct { + int changed; + rs_matrix4x4 *mat; +} ParentData; + +void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { + rs_matrix4x4 temp; + + switch(type) { + case TRANSFORM_TRANSLATE: + rsMatrixLoadTranslate(&temp, data.x, data.y, data.z); + break; + case TRANSFORM_ROTATE: + rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z); + break; + case TRANSFORM_SCALE: + rsMatrixLoadScale(&temp, data.x, data.y, data.z); + break; + } + rsMatrixMultiply(mat, &temp); +} + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + + SgTransform *data = (SgTransform *)v_out; + const ParentData *parent = (const ParentData *)usrData; + + //rsDebug("Transform data", (int)data); + //rsDebug("Entering parent", (int)parent); + + rs_matrix4x4 *localMat = &data->localMat; + rs_matrix4x4 *globalMat = &data->globalMat; + + ParentData toChild; + toChild.changed = 0; + toChild.mat = globalMat; + + //rsDebug("Transform is dirty", data->isDirty); + + // Refresh matrices if dirty + if(data->isDirty) { + data->isDirty = 0; + toChild.changed = 1; + + // Reset our local matrix + rsMatrixLoadIdentity(localMat); + + for(int i = 0; i < 16; i ++) { + if(data->transformTypes[i] == TRANSFORM_NONE) { + break; + } + //rsDebug("Transform adding transformation", transformTypes[i]); + appendTransformation(data->transformTypes[i], data->transforms[i], localMat); + } + } + + //rsDebug("Transform checking parent", (int)0); + + if(parent) { + if(parent->changed) { + toChild.changed = 1; + + rsMatrixLoad(globalMat, parent->mat); + rsMatrixMultiply(globalMat, localMat); + } + } + else { + rsMatrixLoad(globalMat, localMat); + } + + //rsDebug("Transform calling self with child ", (int)data->children.p); + if(data->children.p) { + rsForEach(transformScript, data->children, data->children, (void*)&toChild); + } +} diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh new file mode 100644 index 0000000..7d1721c --- /dev/null +++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform_def.rsh @@ -0,0 +1,35 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.modelviewer) + +#define TRANSFORM_NONE 0 +#define TRANSFORM_TRANSLATE 1 +#define TRANSFORM_ROTATE 2 +#define TRANSFORM_SCALE 3 + +typedef struct __attribute__((packed, aligned(4))) { + rs_matrix4x4 globalMat; + rs_matrix4x4 localMat; + + float4 transforms[16]; + int transformTypes[16]; + + int isDirty; + + rs_allocation children; + +} SgTransform; diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Samples/Android.mk index 9e6ed7e..65ae734 100644 --- a/libs/rs/java/Film/Android.mk +++ b/libs/rs/java/Samples/Android.mk @@ -14,14 +14,18 @@ # limitations under the License. # +ifneq ($(TARGET_SIMULATOR),true) + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript -LOCAL_PACKAGE_NAME := Film +LOCAL_PACKAGE_NAME := Samples include $(BUILD_PACKAGE) + +endif diff --git a/libs/rs/java/Samples/AndroidManifest.xml b/libs/rs/java/Samples/AndroidManifest.xml new file mode 100644 index 0000000..be191f2 --- /dev/null +++ b/libs/rs/java/Samples/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.samples"> + <application android:label="Samples" + android:icon="@drawable/test_pattern"> + <activity android:name="RsList" + android:label="RsList" + android:theme="@android:style/Theme.Black.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name="RsRenderStates" + android:label="RsStates" + android:theme="@android:style/Theme.Black.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/libs/rs/java/Samples/res/drawable/checker.png b/libs/rs/java/Samples/res/drawable/checker.png Binary files differnew file mode 100644 index 0000000..b631e1e --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/checker.png diff --git a/libs/rs/java/Samples/res/drawable/data.png b/libs/rs/java/Samples/res/drawable/data.png Binary files differnew file mode 100644 index 0000000..8e34714 --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/data.png diff --git a/libs/rs/java/Samples/res/drawable/leaf.png b/libs/rs/java/Samples/res/drawable/leaf.png Binary files differnew file mode 100644 index 0000000..3cd3775 --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/leaf.png diff --git a/libs/rs/java/Samples/res/drawable/test_pattern.png b/libs/rs/java/Samples/res/drawable/test_pattern.png Binary files differnew file mode 100644 index 0000000..e7d1455 --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/test_pattern.png diff --git a/libs/rs/java/Samples/res/drawable/torusmap.png b/libs/rs/java/Samples/res/drawable/torusmap.png Binary files differnew file mode 100644 index 0000000..1e08f3b --- /dev/null +++ b/libs/rs/java/Samples/res/drawable/torusmap.png diff --git a/libs/rs/java/Samples/res/raw/multitexf.glsl b/libs/rs/java/Samples/res/raw/multitexf.glsl new file mode 100644 index 0000000..351ff9b --- /dev/null +++ b/libs/rs/java/Samples/res/raw/multitexf.glsl @@ -0,0 +1,12 @@ +varying vec2 varTex0; + +void main() { + vec2 t0 = varTex0.xy; + lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba; + lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba; + lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba; + col0.xyz = col0.xyz*col1.xyz*1.5; + col0.xyz = mix(col0.xyz, col2.xyz, col2.w); + gl_FragColor = col0; +} + diff --git a/libs/rs/java/Samples/res/raw/shaderf.glsl b/libs/rs/java/Samples/res/raw/shaderf.glsl new file mode 100644 index 0000000..fcbe7ee --- /dev/null +++ b/libs/rs/java/Samples/res/raw/shaderf.glsl @@ -0,0 +1,16 @@ + +varying lowp float light0_Diffuse; +varying lowp float light0_Specular; +varying lowp float light1_Diffuse; +varying lowp float light1_Specular; +varying vec2 varTex0; + +void main() { + vec2 t0 = varTex0.xy; + lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; + col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor + light1_Diffuse * UNI_light1_DiffuseColor); + col.xyz += light0_Specular * UNI_light0_SpecularColor; + col.xyz += light1_Specular * UNI_light1_SpecularColor; + gl_FragColor = col; +} + diff --git a/libs/rs/java/Samples/res/raw/shaderv.glsl b/libs/rs/java/Samples/res/raw/shaderv.glsl new file mode 100644 index 0000000..867589c --- /dev/null +++ b/libs/rs/java/Samples/res/raw/shaderv.glsl @@ -0,0 +1,30 @@ +varying float light0_Diffuse; +varying float light0_Specular; +varying float light1_Diffuse; +varying float light1_Specular; +varying vec2 varTex0; + +// This is where actual shader code begins +void main() { + vec4 worldPos = UNI_model * ATTRIB_position; + gl_Position = UNI_proj * worldPos; + + mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); + vec3 worldNorm = model3 * ATTRIB_normal; + vec3 V = normalize(-worldPos.xyz); + + vec3 light0Vec = normalize(UNI_light0_Posision - worldPos.xyz); + vec3 light0R = reflect(light0Vec, worldNorm); + light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse; + float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); + light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular; + + vec3 light1Vec = normalize(UNI_light1_Posision - worldPos.xyz); + vec3 light1R = reflect(light1Vec, worldNorm); + light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse; + float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); + light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular; + + gl_PointSize = 1.0; + varTex0 = ATTRIB_texture0; +} diff --git a/libs/rs/java/Samples/res/raw/torus.a3d b/libs/rs/java/Samples/res/raw/torus.a3d Binary files differnew file mode 100644 index 0000000..0322b01 --- /dev/null +++ b/libs/rs/java/Samples/res/raw/torus.a3d diff --git a/libs/rs/java/Samples/src/com/android/samples/RsList.java b/libs/rs/java/Samples/src/com/android/samples/RsList.java new file mode 100644 index 0000000..0f6b1ac --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsList.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; + +import java.lang.Runtime; + +public class RsList extends Activity { + + private RsListView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new RsListView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onResume(); + mView.onResume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onPause(); + mView.onPause(); + } + +} + diff --git a/libs/rs/java/Samples/src/com/android/samples/RsListRS.java b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java new file mode 100644 index 0000000..aaeea87 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsListRS.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import java.io.Writer; +import java.util.Vector; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; + + +public class RsListRS { + + private final int STATE_LAST_FOCUS = 1; + + private static final String[] DATA_LIST = { + "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", + "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", + "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", + "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", + "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", + "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", + "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria", + "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde", + "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", + "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", + "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", + "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", + "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", + "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland", + "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia", + "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar", + "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", + "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary", + "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", + "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos", + "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", + "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", + "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova", + "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", + "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", + "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas", + "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", + "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar", + "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena", + "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", + "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal", + "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", + "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea", + "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", + "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas", + "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", + "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda", + "Ukraine", "United Arab Emirates", "United Kingdom", + "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", + "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara", + "Yemen", "Yugoslavia", "Zambia", "Zimbabwe" + }; + + int mWidth; + int mHeight; + + public RsListRS() { + } + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + initRS(); + } + + private Resources mRes; + private RenderScriptGL mRS; + private Font mItalic; + + ScriptField_ListAllocs_s mListAllocs; + + private ScriptC_rslist mScript; + + int mLastX; + int mLastY; + + public void onActionDown(int x, int y) { + mScript.set_gDY(0.0f); + + mLastX = x; + mLastY = y; + } + + public void onActionMove(int x, int y) { + int dx = mLastX - x; + int dy = mLastY - y; + + if(Math.abs(dy) <= 2) { + dy = 0; + } + + mScript.set_gDY(dy); + + mLastX = x; + mLastY = y; + } + + private void initRS() { + + mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist, true); + + mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length); + for(int i = 0; i < DATA_LIST.length; i ++) { + ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); + listElem.text = Allocation.createFromString(mRS, DATA_LIST[i]); + mListAllocs.set(listElem, i, false); + } + + mListAllocs.copyAll(); + + mScript.bind_gList(mListAllocs); + + mItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); + mScript.set_gItalic(mItalic); + + mRS.contextBindRootScript(mScript); + } +} + + + diff --git a/libs/rs/java/Samples/src/com/android/samples/RsListView.java b/libs/rs/java/Samples/src/com/android/samples/RsListView.java new file mode 100644 index 0000000..cd66fbb --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsListView.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.KeyEvent; +import android.view.MotionEvent; + +public class RsListView extends RSSurfaceView { + + public RsListView(Context context) { + super(context); + //setFocusable(true); + } + + private RenderScriptGL mRS; + private RsListRS mRender; + + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScript(sc); + mRS.contextSetSurface(w, h, holder.getSurface()); + mRender = new RsListRS(); + mRender.init(mRS, getResources(), w, h); + } + } + + @Override + protected void onDetachedFromWindow() { + if(mRS != null) { + mRS = null; + destroyRenderScript(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + // break point at here + // this method doesn't work when 'extends View' include 'extends ScrollView'. + return super.onKeyDown(keyCode, event); + } + + + @Override + public boolean onTouchEvent(MotionEvent ev) + { + boolean ret = false; + int act = ev.getAction(); + if (act == ev.ACTION_DOWN) { + mRender.onActionDown((int)ev.getX(), (int)ev.getY()); + ret = true; + } + else if (act == ev.ACTION_MOVE) { + mRender.onActionMove((int)ev.getX(), (int)ev.getY()); + ret = true; + } + + return ret; + } +} + + diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStates.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStates.java new file mode 100644 index 0000000..391007e --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStates.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; + +import java.lang.Runtime; + +public class RsRenderStates extends Activity { + + private RsRenderStatesView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new RsRenderStatesView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mView.onResume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mView.onPause(); + } + +} + diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java new file mode 100644 index 0000000..0990da3 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import java.io.Writer; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.renderscript.*; +import android.renderscript.ProgramStore.DepthFunc; +import android.renderscript.Sampler.Value; +import android.util.Log; + + +public class RsRenderStatesRS { + + int mWidth; + int mHeight; + + public RsRenderStatesRS() { + } + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + mOptionsARGB.inScaled = false; + mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; + mMode = 0; + mMaxModes = 9; + initRS(); + } + + private Resources mRes; + private RenderScriptGL mRS; + + private Sampler mLinearClamp; + private Sampler mLinearWrap; + private Sampler mMipLinearWrap; + private Sampler mNearestClamp; + private Sampler mMipLinearAniso8; + private Sampler mMipLinearAniso15; + + private ProgramStore mProgStoreBlendNoneDepth; + private ProgramStore mProgStoreBlendNone; + private ProgramStore mProgStoreBlendAlpha; + private ProgramStore mProgStoreBlendAdd; + + private ProgramFragment mProgFragmentTexture; + private ProgramFragment mProgFragmentColor; + + private ProgramVertex mProgVertex; + private ProgramVertex.MatrixAllocation mPVA; + + // Custom shaders + private ProgramVertex mProgVertexCustom; + private ProgramFragment mProgFragmentCustom; + private ProgramFragment mProgFragmentMultitex; + private ScriptField_VertexShaderConstants_s mVSConst; + private ScriptField_FragentShaderConstants_s mFSConst; + + private ProgramRaster mCullBack; + private ProgramRaster mCullFront; + private ProgramRaster mCullNone; + + private Allocation mTexTorus; + private Allocation mTexOpaque; + private Allocation mTexTransparent; + private Allocation mTexChecker; + + private Mesh mMbyNMesh; + private Mesh mTorus; + + Font mFontSans; + Font mFontSerif; + Font mFontSerifBold; + Font mFontSerifItalic; + Font mFontSerifBoldItalic; + Font mFontMono; + private Allocation mTextAlloc; + + private ScriptC_rsrenderstates mScript; + + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + + int mMode; + int mMaxModes; + + public void onActionDown(int x, int y) { + mMode ++; + mMode = mMode % mMaxModes; + mScript.set_gDisplayMode(mMode); + } + + private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { + + Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, + 2, Mesh.TriangleMeshBuilder.TEXTURE_0); + + for (int y = 0; y <= hResolution; y++) { + final float normalizedY = (float)y / hResolution; + final float yOffset = (normalizedY - 0.5f) * height; + for (int x = 0; x <= wResolution; x++) { + float normalizedX = (float)x / wResolution; + float xOffset = (normalizedX - 0.5f) * width; + tmb.setTexture(normalizedX, normalizedY); + tmb.addVertex(xOffset, yOffset); + } + } + + for (int y = 0; y < hResolution; y++) { + final int curY = y * (wResolution + 1); + final int belowY = (y + 1) * (wResolution + 1); + for (int x = 0; x < wResolution; x++) { + int curV = curY + x; + int belowV = belowY + x; + tmb.addTriangle(curV, belowV, curV + 1); + tmb.addTriangle(belowV, belowV + 1, curV + 1); + } + } + + return tmb.create(true); + } + + private void initProgramStore() { + // Use stock the stock program store object + mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS); + mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NO_DEPTH(mRS); + + // Create a custom program store + ProgramStore.Builder builder = new ProgramStore.Builder(mRS); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, + ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnable(false); + builder.setDepthMask(false); + mProgStoreBlendAlpha = builder.create(); + + mProgStoreBlendAdd = ProgramStore.BLEND_ADD_DEPTH_NO_DEPTH(mRS); + + mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); + mScript.set_gProgStoreBlendNone(mProgStoreBlendNone); + mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha); + mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd); + } + + private void initProgramFragment() { + + ProgramFragment.Builder texBuilder = new ProgramFragment.Builder(mRS); + texBuilder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, + ProgramFragment.Builder.Format.RGBA, 0); + mProgFragmentTexture = texBuilder.create(); + mProgFragmentTexture.bindSampler(mLinearClamp, 0); + + ProgramFragment.Builder colBuilder = new ProgramFragment.Builder(mRS); + colBuilder.setVaryingColor(false); + mProgFragmentColor = colBuilder.create(); + + mScript.set_gProgFragmentColor(mProgFragmentColor); + mScript.set_gProgFragmentTexture(mProgFragmentTexture); + } + + private void initProgramVertex() { + ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS); + mProgVertex = pvb.create(); + + mPVA = new ProgramVertex.MatrixAllocation(mRS); + mProgVertex.bindAllocation(mPVA); + mPVA.setupOrthoWindow(mWidth, mHeight); + + mScript.set_gProgVertex(mProgVertex); + } + + private void initCustomShaders() { + mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); + mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1); + + mScript.bind_gVSConstants(mVSConst); + mScript.bind_gFSConstants(mFSConst); + + // Initialize the shader builder + ProgramVertex.ShaderBuilder pvbCustom = new ProgramVertex.ShaderBuilder(mRS); + // Specify the resource that contains the shader string + pvbCustom.setShader(mRes, R.raw.shaderv); + // Use a script field to spcify the input layout + pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); + // Define the constant input layout + pvbCustom.addConstant(mVSConst.getAllocation().getType()); + mProgVertexCustom = pvbCustom.create(); + // Bind the source of constant data + mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); + + ProgramFragment.ShaderBuilder pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + // Specify the resource that contains the shader string + pfbCustom.setShader(mRes, R.raw.shaderf); + //Tell the builder how many textures we have + pfbCustom.setTextureCount(1); + // Define the constant input layout + pfbCustom.addConstant(mFSConst.getAllocation().getType()); + mProgFragmentCustom = pfbCustom.create(); + // Bind the source of constant data + mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); + + pfbCustom = new ProgramFragment.ShaderBuilder(mRS); + pfbCustom.setShader(mRes, R.raw.multitexf); + pfbCustom.setTextureCount(3); + mProgFragmentMultitex = pfbCustom.create(); + + mScript.set_gProgVertexCustom(mProgVertexCustom); + mScript.set_gProgFragmentCustom(mProgFragmentCustom); + mScript.set_gProgFragmentMultitex(mProgFragmentMultitex); + } + + private Allocation loadTextureRGB(int id) { + final Allocation allocation = Allocation.createFromBitmapResource(mRS, mRes, + id, Element.RGB_565(mRS), true); + allocation.uploadToTexture(0); + return allocation; + } + + private Allocation loadTextureARGB(int id) { + Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); + final Allocation allocation = Allocation.createFromBitmap(mRS, b, Element.RGBA_8888(mRS), true); + allocation.uploadToTexture(0); + return allocation; + } + + private void loadImages() { + mTexTorus = loadTextureRGB(R.drawable.torusmap); + mTexOpaque = loadTextureRGB(R.drawable.data); + mTexTransparent = loadTextureARGB(R.drawable.leaf); + mTexChecker = loadTextureRGB(R.drawable.checker); + + mScript.set_gTexTorus(mTexTorus); + mScript.set_gTexOpaque(mTexOpaque); + mScript.set_gTexTransparent(mTexTransparent); + mScript.set_gTexChecker(mTexChecker); + } + + private void initFonts() { + // Sans font by family name + mFontSans = Font.createFromFamily(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); + // Create font by file name + mFontSerif = Font.create(mRS, mRes, "DroidSerif-Regular.ttf", 8); + // Create fonts by family and style + mFontSerifBold = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD, 8); + mFontSerifItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.ITALIC, 8); + mFontSerifBoldItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); + mFontMono = Font.createFromFamily(mRS, mRes, "mono", Font.Style.NORMAL, 8); + + mTextAlloc = Allocation.createFromString(mRS, "String from allocation"); + + mScript.set_gFontSans(mFontSans); + mScript.set_gFontSerif(mFontSerif); + mScript.set_gFontSerifBold(mFontSerifBold); + mScript.set_gFontSerifItalic(mFontSerifItalic); + mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic); + mScript.set_gFontMono(mFontMono); + mScript.set_gTextAlloc(mTextAlloc); + } + + private void initMesh() { + mMbyNMesh = getMbyNMesh(256, 256, 10, 10); + mScript.set_gMbyNMesh(mMbyNMesh); + + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); + FileA3D.IndexEntry entry = model.getIndexEntry(0); + if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) { + Log.e("rs", "could not load model"); + } + else { + mTorus = (Mesh)entry.getObject(); + mScript.set_gTorusMesh(mTorus); + } + } + + private void initSamplers() { + Sampler.Builder bs = new Sampler.Builder(mRS); + bs.setMin(Sampler.Value.LINEAR); + bs.setMag(Sampler.Value.LINEAR); + bs.setWrapS(Sampler.Value.WRAP); + bs.setWrapT(Sampler.Value.WRAP); + mLinearWrap = bs.create(); + + mLinearClamp = Sampler.CLAMP_LINEAR(mRS); + mNearestClamp = Sampler.CLAMP_NEAREST(mRS); + mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS); + + bs = new Sampler.Builder(mRS); + bs.setMin(Sampler.Value.LINEAR_MIP_LINEAR); + bs.setMag(Sampler.Value.LINEAR); + bs.setWrapS(Sampler.Value.WRAP); + bs.setWrapT(Sampler.Value.WRAP); + bs.setAnisotropy(8.0f); + mMipLinearAniso8 = bs.create(); + bs.setAnisotropy(15.0f); + mMipLinearAniso15 = bs.create(); + + mScript.set_gLinearClamp(mLinearClamp); + mScript.set_gLinearWrap(mLinearWrap); + mScript.set_gMipLinearWrap(mMipLinearWrap); + mScript.set_gMipLinearAniso8(mMipLinearAniso8); + mScript.set_gMipLinearAniso15(mMipLinearAniso15); + mScript.set_gNearestClamp(mNearestClamp); + } + + private void initProgramRaster() { + mCullBack = ProgramRaster.CULL_BACK(mRS); + mCullFront = ProgramRaster.CULL_FRONT(mRS); + mCullNone = ProgramRaster.CULL_NONE(mRS); + + mScript.set_gCullBack(mCullBack); + mScript.set_gCullFront(mCullFront); + mScript.set_gCullNone(mCullNone); + } + + private void initRS() { + + mScript = new ScriptC_rsrenderstates(mRS, mRes, R.raw.rsrenderstates, true); + + initSamplers(); + initProgramStore(); + initProgramFragment(); + initProgramVertex(); + initFonts(); + loadImages(); + initMesh(); + initProgramRaster(); + initCustomShaders(); + + mRS.contextBindRootScript(mScript); + } +} + + + diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java new file mode 100644 index 0000000..c434c09 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.samples; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.KeyEvent; +import android.view.MotionEvent; + +public class RsRenderStatesView extends RSSurfaceView { + + public RsRenderStatesView(Context context) { + super(context); + //setFocusable(true); + } + + private RenderScriptGL mRS; + private RsRenderStatesRS mRender; + + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScript(sc); + mRS.contextSetSurface(w, h, holder.getSurface()); + mRender = new RsRenderStatesRS(); + mRender.init(mRS, getResources(), w, h); + } + } + + @Override + protected void onDetachedFromWindow() { + if(mRS != null) { + mRS = null; + destroyRenderScript(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + // break point at here + // this method doesn't work when 'extends View' include 'extends ScrollView'. + return super.onKeyDown(keyCode, event); + } + + + @Override + public boolean onTouchEvent(MotionEvent ev) + { + boolean ret = false; + int act = ev.getAction(); + if (act == ev.ACTION_DOWN) { + mRender.onActionDown((int)ev.getX(), (int)ev.getY()); + ret = true; + } + + return ret; + } +} + + diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs new file mode 100644 index 0000000..f760ad0 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs @@ -0,0 +1,71 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.samples) + +#include "rs_graphics.rsh" + +float gDY; + +rs_font gItalic; + +typedef struct ListAllocs_s { + rs_allocation text; +} ListAllocs; + +ListAllocs *gList; + +void init() { + gDY = 0.0f; +} + +int textPos = 0; + +int root(int launchID) { + + rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); + rsgClearDepth(1.0f); + + textPos -= (int)gDY*2; + gDY *= 0.95; + + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + rsgBindFont(gItalic); + color(0.2, 0.2, 0.2, 0); + + rs_allocation listAlloc = rsGetAllocation(gList); + int allocSize = rsAllocationGetDimX(listAlloc); + + int width = rsgGetWidth(); + int height = rsgGetHeight(); + + int itemHeight = 80; + int currentYPos = itemHeight + textPos; + + for(int i = 0; i < allocSize; i ++) { + if(currentYPos - itemHeight > height) { + break; + } + + if(currentYPos > 0) { + rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0); + rsgDrawText(gList[i].text, 30, currentYPos - 32); + } + currentYPos += itemHeight; + } + + return 10; +} diff --git a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs new file mode 100644 index 0000000..8be35f8 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs @@ -0,0 +1,583 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.samples) + +#include "rs_graphics.rsh" +#include "shader_def.rsh" + +rs_program_vertex gProgVertex; +rs_program_fragment gProgFragmentColor; +rs_program_fragment gProgFragmentTexture; + +rs_program_store gProgStoreBlendNoneDepth; +rs_program_store gProgStoreBlendNone; +rs_program_store gProgStoreBlendAlpha; +rs_program_store gProgStoreBlendAdd; + +rs_allocation gTexOpaque; +rs_allocation gTexTorus; +rs_allocation gTexTransparent; +rs_allocation gTexChecker; + +rs_mesh gMbyNMesh; +rs_mesh gTorusMesh; + +rs_font gFontSans; +rs_font gFontSerif; +rs_font gFontSerifBold; +rs_font gFontSerifItalic; +rs_font gFontSerifBoldItalic; +rs_font gFontMono; +rs_allocation gTextAlloc; + +int gDisplayMode; + +rs_sampler gLinearClamp; +rs_sampler gLinearWrap; +rs_sampler gMipLinearWrap; +rs_sampler gMipLinearAniso8; +rs_sampler gMipLinearAniso15; +rs_sampler gNearestClamp; + +rs_program_raster gCullBack; +rs_program_raster gCullFront; +rs_program_raster gCullNone; + +// Custom vertex shader compunents +VertexShaderConstants *gVSConstants; +FragentShaderConstants *gFSConstants; +// Export these out to easily set the inputs to shader +VertexShaderInputs *gVSInputs; +// Custom shaders we use for lighting +rs_program_vertex gProgVertexCustom; +rs_program_fragment gProgFragmentCustom; +rs_program_fragment gProgFragmentMultitex; + +float gDt = 0; + +void init() { +} + +void displayFontSamples() { + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + int yPos = 100; + rsgBindFont(gFontSans); + rsgDrawText("Sans font sample", 30, yPos); + yPos += 30; + rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f); + rsgBindFont(gFontSerif); + rsgDrawText("Serif font sample", 30, yPos); + yPos += 30; + rsgFontColor(0.7f, 0.7f, 0.7f, 1.0f); + rsgBindFont(gFontSerifBold); + rsgDrawText("Serif Bold font sample", 30, yPos); + yPos += 30; + rsgFontColor(0.5f, 0.5f, 0.9f, 1.0f); + rsgBindFont(gFontSerifItalic); + rsgDrawText("Serif Italic font sample", 30, yPos); + yPos += 30; + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontSerifBoldItalic); + rsgDrawText("Serif Bold Italic font sample", 30, yPos); + yPos += 30; + rsgBindFont(gFontMono); + rsgDrawText("Monospace font sample", 30, yPos); + yPos += 50; + + // Now use text metrics to center the text + uint width = rsgGetWidth(); + uint height = rsgGetHeight(); + int left = 0, right = 0, top = 0, bottom = 0; + + rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); + rsgBindFont(gFontSerifBoldItalic); + + rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); + int centeredPos = width / 2 - (right - left) / 2; + rsgDrawText(gTextAlloc, centeredPos, yPos); + yPos += 30; + + const char* text = "Centered Text Sample"; + rsgMeasureText(text, &left, &right, &top, &bottom); + centeredPos = width / 2 - (right - left) / 2; + rsgDrawText(text, centeredPos, yPos); + yPos += 30; + + rsgBindFont(gFontSans); + text = "More Centered Text Samples"; + rsgMeasureText(text, &left, &right, &top, &bottom); + centeredPos = width / 2 - (right - left) / 2; + rsgDrawText(text, centeredPos, yPos); + yPos += 30; + + // Now draw bottom and top right aligned text + text = "Top-right aligned text"; + rsgMeasureText(text, &left, &right, &top, &bottom); + rsgDrawText(text, width - right, top); + + text = "Top-left"; + rsgMeasureText(text, &left, &right, &top, &bottom); + rsgDrawText(text, -left, top); + + text = "Bottom-right aligned text"; + rsgMeasureText(text, &left, &right, &top, &bottom); + rsgDrawText(text, width - right, height + bottom); + +} + +void bindProgramVertexOrtho() { + // Default vertex sahder + rsgBindProgramVertex(gProgVertex); + // Setup the projectioni matrix + rs_matrix4x4 proj; + rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); + rsgProgramVertexLoadProjectionMatrix(&proj); +} + +void displayShaderSamples() { + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + + float startX = 0, startY = 0; + float width = 256, height = 256; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + + startX = 200; startY = 0; + width = 128; height = 128; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + + rsgBindProgramStore(gProgStoreBlendAlpha); + rsgBindTexture(gProgFragmentTexture, 0, gTexTransparent); + startX = 0; startY = 200; + width = 128; height = 128; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + + // Fragment program with simple color + rsgBindProgramFragment(gProgFragmentColor); + rsgProgramFragmentConstantColor(gProgFragmentColor, 0.9, 0.3, 0.3, 1); + rsgDrawRect(200, 300, 350, 450, 0); + rsgProgramFragmentConstantColor(gProgFragmentColor, 0.3, 0.9, 0.3, 1); + rsgDrawRect(50, 400, 400, 600, 0); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Texture shader", 10, 50); + rsgDrawText("Alpha-blended texture shader", 10, 280); + rsgDrawText("Flat color shader", 100, 450); +} + +void displayBlendingSamples() { + int i; + + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + rsgBindProgramFragment(gProgFragmentColor); + + rsgBindProgramStore(gProgStoreBlendNone); + for(i = 0; i < 3; i ++) { + float iPlusOne = (float)(i + 1); + rsgProgramFragmentConstantColor(gProgFragmentColor, + 0.1f*iPlusOne, 0.2f*iPlusOne, 0.3f*iPlusOne, 1); + float yPos = 150 * (float)i; + rsgDrawRect(0, yPos, 200, yPos + 200, 0); + } + + rsgBindProgramStore(gProgStoreBlendAlpha); + for(i = 0; i < 3; i ++) { + float iPlusOne = (float)(i + 1); + rsgProgramFragmentConstantColor(gProgFragmentColor, + 0.2f*iPlusOne, 0.3f*iPlusOne, 0.1f*iPlusOne, 0.5); + float yPos = 150 * (float)i; + rsgDrawRect(150, yPos, 350, yPos + 200, 0); + } + + rsgBindProgramStore(gProgStoreBlendAdd); + for(i = 0; i < 3; i ++) { + float iPlusOne = (float)(i + 1); + rsgProgramFragmentConstantColor(gProgFragmentColor, + 0.3f*iPlusOne, 0.1f*iPlusOne, 0.2f*iPlusOne, 0.5); + float yPos = 150 * (float)i; + rsgDrawRect(300, yPos, 500, yPos + 200, 0); + } + + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("No Blending", 10, 50); + rsgDrawText("Alpha Blending", 160, 150); + rsgDrawText("Additive Blending", 320, 250); + +} + +void displayMeshSamples() { + + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadTranslate(&matrix, 128, 128, 0); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + + rsgDrawMesh(gMbyNMesh); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("User gen 10 by 10 grid mesh", 10, 250); +} + +void displayTextureSamplers() { + + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + + // Linear clamp + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + float startX = 0, startY = 0; + float width = 300, height = 300; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1.1, + startX + width, startY + height, 0, 1.1, 1.1, + startX + width, startY, 0, 1.1, 0); + + // Linear Wrap + rsgBindSampler(gProgFragmentTexture, 0, gLinearWrap); + startX = 0; startY = 300; + width = 300; height = 300; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1.1, + startX + width, startY + height, 0, 1.1, 1.1, + startX + width, startY, 0, 1.1, 0); + + // Nearest + rsgBindSampler(gProgFragmentTexture, 0, gNearestClamp); + startX = 300; startY = 0; + width = 300; height = 300; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1.1, + startX + width, startY + height, 0, 1.1, 1.1, + startX + width, startY, 0, 1.1, 0); + + rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap); + startX = 300; startY = 300; + width = 300; height = 300; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1.5, + startX + width, startY + height, 0, 1.5, 1.5, + startX + width, startY, 0, 1.5, 0); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Filtering: linear clamp", 10, 290); + rsgDrawText("Filtering: linear wrap", 10, 590); + rsgDrawText("Filtering: nearest clamp", 310, 290); + rsgDrawText("Filtering: miplinear wrap", 310, 590); +} + +float gTorusRotation = 0; + +void displayCullingSamples() { + rsgBindProgramVertex(gProgVertex); + // Setup the projectioni matrix with 60 degree field of view + rs_matrix4x4 proj; + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNoneDepth); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); + + // Aplly a rotation to our mesh + gTorusRotation += 50.0f * gDt; + if(gTorusRotation > 360.0f) { + gTorusRotation -= 360.0f; + } + + rs_matrix4x4 matrix; + // Position our model on the screen + rsMatrixLoadTranslate(&matrix, -2.0f, 0.0f, -10.0f); + rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + // Use front face culling + rsgBindProgramRaster(gCullFront); + rsgDrawMesh(gTorusMesh); + + rsMatrixLoadTranslate(&matrix, 2.0f, 0.0f, -10.0f); + rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + // Use back face culling + rsgBindProgramRaster(gCullBack); + rsgDrawMesh(gTorusMesh); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Displaying mesh front/back face culling", 10, rsgGetHeight() - 10); +} + +float gLight0Rotation = 0; +float gLight1Rotation = 0; + +void setupCustomShaderLights() { + float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f}; + float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f}; + float3 light0DiffCol = {0.9f, 0.7f, 0.7f}; + float3 light0SpecCol = {0.9f, 0.6f, 0.6f}; + float3 light1DiffCol = {0.5f, 0.5f, 0.9f}; + float3 light1SpecCol = {0.5f, 0.5f, 0.9f}; + + gLight0Rotation += 50.0f * gDt; + if(gLight0Rotation > 360.0f) { + gLight0Rotation -= 360.0f; + } + gLight1Rotation -= 50.0f * gDt; + if(gLight1Rotation > 360.0f) { + gLight1Rotation -= 360.0f; + } + + rs_matrix4x4 l0Mat; + rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f); + light0Pos = rsMatrixMultiply(&l0Mat, light0Pos); + rs_matrix4x4 l1Mat; + rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f); + light1Pos = rsMatrixMultiply(&l1Mat, light1Pos); + + // Set light 0 properties + gVSConstants->light0_Posision.x = light0Pos.x; + gVSConstants->light0_Posision.y = light0Pos.y; + gVSConstants->light0_Posision.z = light0Pos.z; + gVSConstants->light0_Diffuse = 1.0f; + gVSConstants->light0_Specular = 0.5f; + gVSConstants->light0_CosinePower = 40.0f; + // Set light 1 properties + gVSConstants->light1_Posision.x = light1Pos.x; + gVSConstants->light1_Posision.y = light1Pos.y; + gVSConstants->light1_Posision.z = light1Pos.z; + gVSConstants->light1_Diffuse = 1.0f; + gVSConstants->light1_Specular = 0.7f; + gVSConstants->light1_CosinePower = 50.0f; + rsAllocationMarkDirty(rsGetAllocation(gVSConstants)); + + // Update fragmetn shader constants + // Set light 0 colors + gFSConstants->light0_DiffuseColor = light0DiffCol; + gFSConstants->light0_SpecularColor = light0SpecCol; + // Set light 1 colors + gFSConstants->light1_DiffuseColor = light1DiffCol; + gFSConstants->light1_SpecularColor = light1SpecCol; + rsAllocationMarkDirty(rsGetAllocation(gFSConstants)); +} + +void displayCustomShaderSamples() { + + // Update vertex shader constants + // Load model matrix + // Aplly a rotation to our mesh + gTorusRotation += 50.0f * gDt; + if(gTorusRotation > 360.0f) { + gTorusRotation -= 360.0f; + } + + // Position our model on the screen + rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f); + rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f); + // Setup the projectioni matrix + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); + setupCustomShaderLights(); + + rsgBindProgramVertex(gProgVertexCustom); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNoneDepth); + rsgBindProgramFragment(gProgFragmentCustom); + rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp); + rsgBindTexture(gProgFragmentCustom, 0, gTexTorus); + + // Use back face culling + rsgBindProgramRaster(gCullBack); + rsgDrawMesh(gTorusMesh); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Custom shader sample", 10, rsgGetHeight() - 10); +} + +void displayMultitextureSample() { + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentMultitex); + rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp); + rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap); + rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp); + rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker); + rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus); + rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent); + + float startX = 0, startY = 0; + float width = 256, height = 256; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + rsgDrawText("Custom shader with multitexturing", 10, 280); +} + +float gAnisoTime = 0.0f; +uint anisoMode = 0; +void displayAnisoSample() { + + gAnisoTime += gDt; + + rsgBindProgramVertex(gProgVertex); + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rs_matrix4x4 proj; + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rs_matrix4x4 matrix; + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentTexture); + rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -10.0f); + rsMatrixRotate(&matrix, -80, 1.0f, 0.0f, 0.0f); + rsgProgramVertexLoadModelMatrix(&matrix); + + rsgBindProgramRaster(gCullNone); + + rsgBindTexture(gProgFragmentTexture, 0, gTexChecker); + + if(gAnisoTime >= 5.0f) { + gAnisoTime = 0.0f; + anisoMode ++; + anisoMode = anisoMode % 3; + } + + if(anisoMode == 0) { + rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso8); + } + else if(anisoMode == 1) { + rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso15); + } + else { + rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap); + } + + float startX = -15; + float startY = -15; + float width = 30; + float height = 30; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 10, + startX + width, startY + height, 0, 10, 10, + startX + width, startY, 0, 10, 0); + + rsgBindProgramRaster(gCullBack); + + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgBindFont(gFontMono); + if(anisoMode == 0) { + rsgDrawText("Anisotropic filtering 8", 10, 40); + } + else if(anisoMode == 1) { + rsgDrawText("Anisotropic filtering 15", 10, 40); + } + else { + rsgDrawText("Miplinear filtering", 10, 40); + } +} + +int root(int launchID) { + + gDt = rsGetDt(); + + rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); + rsgClearDepth(1.0f); + + switch(gDisplayMode) { + case 0: + displayFontSamples(); + break; + case 1: + displayShaderSamples(); + break; + case 2: + displayBlendingSamples(); + break; + case 3: + displayMeshSamples(); + break; + case 4: + displayTextureSamplers(); + break; + case 5: + displayCullingSamples(); + break; + case 6: + displayCustomShaderSamples(); + break; + case 7: + displayMultitextureSample(); + break; + case 8: + displayAnisoSample(); + break; + } + + return 10; +} diff --git a/libs/rs/java/Samples/src/com/android/samples/shader_def.rsh b/libs/rs/java/Samples/src/com/android/samples/shader_def.rsh new file mode 100644 index 0000000..e3f6206 --- /dev/null +++ b/libs/rs/java/Samples/src/com/android/samples/shader_def.rsh @@ -0,0 +1,47 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.samples) + +typedef struct VertexShaderConstants_s { + rs_matrix4x4 model; + rs_matrix4x4 proj; + float3 light0_Posision; + float light0_Diffuse; + float light0_Specular; + float light0_CosinePower; + + float3 light1_Posision; + float light1_Diffuse; + float light1_Specular; + float light1_CosinePower; +} VertexShaderConstants; + +typedef struct FragentShaderConstants_s { + float3 light0_DiffuseColor; + float3 light0_SpecularColor; + + float3 light1_DiffuseColor; + float3 light1_SpecularColor; + +} FragentShaderConstants; + +typedef struct VertexShaderInputs_s { + float4 position; + float3 normal; + float2 texture0; +} VertexShaderInputs; + diff --git a/libs/rs/java/tests/Android.mk b/libs/rs/java/tests/Android.mk new file mode 100644 index 0000000..6c992d5 --- /dev/null +++ b/libs/rs/java/tests/Android.mk @@ -0,0 +1,30 @@ +# +# Copyright (C) 2008 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. +# + +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) + +LOCAL_PACKAGE_NAME := RSTest + +include $(BUILD_PACKAGE) + +endif diff --git a/libs/rs/java/Film/AndroidManifest.xml b/libs/rs/java/tests/AndroidManifest.xml index a5ce8a1..b660398 100644 --- a/libs/rs/java/Film/AndroidManifest.xml +++ b/libs/rs/java/tests/AndroidManifest.xml @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.film"> - <application android:label="Film"> - <activity android:name="Film" - android:screenOrientation="portrait" - android:theme="@android:style/Theme.Black.NoTitleBar"> + package="com.android.rs.test"> + <application + android:label="_RS_Test" + android:icon="@drawable/test_pattern"> + <activity android:name="RSTest" + android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/libs/rs/java/tests/res/drawable/test_pattern.png b/libs/rs/java/tests/res/drawable/test_pattern.png Binary files differnew file mode 100644 index 0000000..e7d1455 --- /dev/null +++ b/libs/rs/java/tests/res/drawable/test_pattern.png diff --git a/libs/rs/java/Film/src/com/android/film/Film.java b/libs/rs/java/tests/src/com/android/rs/test/RSTest.java index 6e99816..c264649 100644 --- a/libs/rs/java/Film/src/com/android/film/Film.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.film; +package com.android.rs.test; import android.renderscript.RSSurfaceView; import android.renderscript.RenderScript; @@ -37,33 +37,31 @@ import android.widget.ListView; import java.lang.Runtime; -public class Film extends Activity { +public class RSTest extends Activity { //EventListener mListener = new EventListener(); private static final String LOG_TAG = "libRS_jni"; private static final boolean DEBUG = false; private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; - private FilmView mView; + private RSTestView mView; // get the current looper (from your Activity UI thread for instance - - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Create our Preview view and set it as the content of our // Activity - mView = new FilmView(this); + mView = new RSTestView(this); setContentView(mView); } @Override protected void onResume() { // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus + // to take appropriate action when the activity loses focus super.onResume(); mView.onResume(); } @@ -71,14 +69,11 @@ public class Film extends Activity { @Override protected void onPause() { // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus + // to take appropriate action when the activity loses focus super.onPause(); mView.onPause(); - - Runtime.getRuntime().exit(0); } - static void log(String message) { if (LOG_ENABLED) { Log.v(LOG_TAG, message); @@ -87,4 +82,3 @@ public class Film extends Activity { } - diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java new file mode 100644 index 0000000..835dea2 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.rs.test; + +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; +import java.util.ArrayList; +import java.util.ListIterator; +import java.util.Timer; +import java.util.TimerTask; + + +public class RSTestCore { + int mWidth; + int mHeight; + + public RSTestCore() { + } + + private Resources mRes; + private RenderScriptGL mRS; + + private Font mFont; + ScriptField_ListAllocs_s mListAllocs; + int mLastX; + int mLastY; + private ScriptC_rslist mScript; + + private ArrayList<UnitTest> unitTests; + private ListIterator<UnitTest> test_iter; + private UnitTest activeTest; + private boolean stopTesting; + + /* Periodic timer for ensuring future tests get scheduled */ + private Timer mTimer; + public static final int RS_TIMER_PERIOD = 100; + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + stopTesting = false; + + mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist, true); + + unitTests = new ArrayList<UnitTest>(); + + unitTests.add(new UT_primitives(this, mRes)); + unitTests.add(new UT_fp_mad(this, mRes)); + /* + unitTests.add(new UnitTest(null, "<Pass>", 1)); + unitTests.add(new UnitTest()); + unitTests.add(new UnitTest(null, "<Fail>", -1)); + + for (int i = 0; i < 20; i++) { + unitTests.add(new UnitTest(null, "<Pass>", 1)); + } + */ + + UnitTest [] uta = new UnitTest[unitTests.size()]; + uta = unitTests.toArray(uta); + + mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length); + for (int i = 0; i < uta.length; i++) { + ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); + listElem.text = Allocation.createFromString(mRS, uta[i].name); + listElem.result = uta[i].result; + mListAllocs.set(listElem, i, false); + uta[i].setItem(listElem); + } + + mListAllocs.copyAll(); + + mScript.bind_gList(mListAllocs); + + mFont = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD, 8); + mScript.set_gFont(mFont); + + mRS.contextBindRootScript(mScript); + + test_iter = unitTests.listIterator(); + refreshTestResults(); /* Kick off the first test */ + + TimerTask pTask = new TimerTask() { + public void run() { + refreshTestResults(); + } + }; + + mTimer = new Timer(); + mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD); + } + + public void checkAndRunNextTest() { + if (activeTest != null) { + if (!activeTest.isAlive()) { + /* Properly clean up on our last test */ + try { + activeTest.join(); + } + catch (InterruptedException e) { + } + activeTest = null; + } + } + + if (!stopTesting && activeTest == null) { + if (test_iter.hasNext()) { + activeTest = test_iter.next(); + activeTest.start(); + /* This routine will only get called once when a new test + * should start running. The message handler in UnitTest.java + * ensures this. */ + } + else { + if (mTimer != null) { + mTimer.cancel(); + mTimer.purge(); + mTimer = null; + } + } + } + } + + public void refreshTestResults() { + checkAndRunNextTest(); + + if (mListAllocs != null && mScript != null && mRS != null) { + mListAllocs.copyAll(); + + mScript.bind_gList(mListAllocs); + mRS.contextBindRootScript(mScript); + } + } + + public void cleanup() { + stopTesting = true; + UnitTest t = activeTest; + + /* Stop periodic refresh of testing */ + if (mTimer != null) { + mTimer.cancel(); + mTimer.purge(); + mTimer = null; + } + + /* Wait to exit until we finish the current test */ + if (t != null) { + try { + t.join(); + } + catch (InterruptedException e) { + } + t = null; + } + + } + + public void newTouchPosition(float x, float y, float pressure, int id) { + } + + public void onActionDown(int x, int y) { + mScript.set_gDY(0.0f); + mLastX = x; + mLastY = y; + refreshTestResults(); + } + + public void onActionMove(int x, int y) { + int dx = mLastX - x; + int dy = mLastY - y; + + if (Math.abs(dy) <= 2) { + dy = 0; + } + + mScript.set_gDY(dy); + + mLastX = x; + mLastY = y; + refreshTestResults(); + } +} diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java new file mode 100644 index 0000000..c65f8c6 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.rs.test; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.KeyEvent; +import android.view.MotionEvent; + +public class RSTestView extends RSSurfaceView { + + public RSTestView(Context context) { + super(context); + //setFocusable(true); + } + + private RenderScriptGL mRS; + private RSTestCore mRender; + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + mRS = createRenderScript(sc); + mRS.contextSetSurface(w, h, holder.getSurface()); + mRender = new RSTestCore(); + mRender.init(mRS, getResources(), w, h); + } + } + + @Override + protected void onDetachedFromWindow() { + if(mRS != null) { + mRender.cleanup(); + mRS = null; + destroyRenderScript(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) + { + boolean ret = false; + int act = ev.getAction(); + if (act == ev.ACTION_DOWN) { + mRender.onActionDown((int)ev.getX(), (int)ev.getY()); + ret = true; + } + else if (act == ev.ACTION_MOVE) { + mRender.onActionMove((int)ev.getX(), (int)ev.getY()); + ret = true; + } + + return ret; + } +} + + diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java new file mode 100644 index 0000000..9d57e90 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_fp_mad.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package com.android.rs.test; + +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_fp_mad extends UnitTest { + private Resources mRes; + + protected UT_fp_mad(RSTestCore rstc, Resources res) { + super(rstc, "Fp_Mad"); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(); + ScriptC_fp_mad s = new ScriptC_fp_mad(pRS, mRes, R.raw.fp_mad, true); + pRS.mMessageCallback = mRsMessage; + s.invoke_fp_mad_test(0, 0); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java new file mode 100644 index 0000000..da995da --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package com.android.rs.test; + +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_primitives extends UnitTest { + private Resources mRes; + + protected UT_primitives(RSTestCore rstc, Resources res) { + super(rstc, "Primitives"); + mRes = res; + } + + private boolean initializeGlobals(ScriptC_primitives s) { + float pF = s.get_floatTest(); + if (pF != 1.99f) { + return false; + } + s.set_floatTest(2.99f); + + double pD = s.get_doubleTest(); + if (pD != 2.05) { + return false; + } + s.set_doubleTest(3.05); + + byte pC = s.get_charTest(); + if (pC != -8) { + return false; + } + s.set_charTest((byte)-16); + + short pS = s.get_shortTest(); + if (pS != -16) { + return false; + } + s.set_shortTest((short)-32); + + int pI = s.get_intTest(); + if (pI != -32) { + return false; + } + s.set_intTest(-64); + + long pL = s.get_longTest(); + if (pL != 17179869184l) { + return false; + } + s.set_longTest(17179869185l); + + long puL = s.get_ulongTest(); + if (puL != 4611686018427387904L) { + return false; + } + s.set_ulongTest(4611686018427387903L); + + + long pLL = s.get_longlongTest(); + if (pLL != 68719476736L) { + return false; + } + s.set_longlongTest(68719476735L); + + long pu64 = s.get_uint64_tTest(); + if (pu64 != 117179869184l) { + return false; + } + s.set_uint64_tTest(117179869185l); + + return true; + } + + public void run() { + RenderScript pRS = RenderScript.create(); + ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives, true); + pRS.mMessageCallback = mRsMessage; + if (!initializeGlobals(s)) { + // initializeGlobals failed + result = -1; + } else { + s.invoke_primitives_test(0, 0); + pRS.finish(); + waitForMessage(); + } + pRS.destroy(); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java new file mode 100644 index 0000000..90bb8a3 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package com.android.rs.test; +import android.renderscript.RenderScript.RSMessage; +import android.util.Log; + +public class UnitTest extends Thread { + public String name; + public int result; + private ScriptField_ListAllocs_s.Item mItem; + private RSTestCore mRSTC; + private boolean msgHandled; + + /* These constants must match those in shared.rsh */ + public static final int RS_MSG_TEST_PASSED = 100; + public static final int RS_MSG_TEST_FAILED = 101; + + private static int numTests = 0; + public int testID; + + protected UnitTest(RSTestCore rstc, String n, int initResult) { + super(); + mRSTC = rstc; + name = n; + msgHandled = false; + result = initResult; + testID = numTests++; + } + + protected UnitTest(RSTestCore rstc, String n) { + this(rstc, n, 0); + } + + protected UnitTest(RSTestCore rstc) { + this (rstc, "<Unknown>"); + } + + protected UnitTest() { + this (null); + } + + protected RSMessage mRsMessage = new RSMessage() { + public void run() { + if (result == 0) { + switch (mID) { + case RS_MSG_TEST_PASSED: + result = 1; + break; + case RS_MSG_TEST_FAILED: + result = -1; + break; + default: + android.util.Log.v("RenderScript", "Unit test got unexpected message"); + return; + } + } + + if (mItem != null) { + mItem.result = result; + msgHandled = true; + try { + mRSTC.refreshTestResults(); + } + catch (IllegalStateException e) { + /* Ignore the case where our message receiver has been + disconnected. This happens when we leave the application + before it finishes running all of the unit tests. */ + } + } + } + }; + + public void waitForMessage() { + while (!msgHandled) { + yield(); + } + } + + public void setItem(ScriptField_ListAllocs_s.Item item) { + mItem = item; + } + + public void run() { + /* This method needs to be implemented for each subclass */ + if (mRSTC != null) { + mRSTC.refreshTestResults(); + } + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs new file mode 100644 index 0000000..066fab8 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs @@ -0,0 +1,175 @@ +#include "shared.rsh" + +const int TEST_COUNT = 1; + +#pragma rs export_func(fp_mad_test) + +static float data_f1[1025]; +static float4 data_f4[1025]; + +static void test_mad4(uint32_t index) { + start(); + + float total = 0; + // Do ~1 billion ops + for (int ct=0; ct < 1000 * (1000 / 80); ct++) { + for (int i=0; i < (1000); i++) { + data_f4[i] = (data_f4[i] * 0.02f + + data_f4[i+1] * 0.04f + + data_f4[i+2] * 0.05f + + data_f4[i+3] * 0.1f + + data_f4[i+4] * 0.2f + + data_f4[i+5] * 0.2f + + data_f4[i+6] * 0.1f + + data_f4[i+7] * 0.05f + + data_f4[i+8] * 0.04f + + data_f4[i+9] * 0.02f + 1.f); + } + } + + float time = end(index); + rsDebug("fp_mad4 M ops", 1000.f / time); +} + +static void test_mad(uint32_t index) { + start(); + + float total = 0; + // Do ~1 billion ops + for (int ct=0; ct < 1000 * (1000 / 20); ct++) { + for (int i=0; i < (1000); i++) { + data_f1[i] = (data_f1[i] * 0.02f + + data_f1[i+1] * 0.04f + + data_f1[i+2] * 0.05f + + data_f1[i+3] * 0.1f + + data_f1[i+4] * 0.2f + + data_f1[i+5] * 0.2f + + data_f1[i+6] * 0.1f + + data_f1[i+7] * 0.05f + + data_f1[i+8] * 0.04f + + data_f1[i+9] * 0.02f + 1.f); + } + } + + float time = end(index); + rsDebug("fp_mad M ops", 1000.f / time); +} + +static void test_norm(uint32_t index) { + start(); + + float total = 0; + // Do ~10 M ops + for (int ct=0; ct < 1000 * 10; ct++) { + for (int i=0; i < (1000); i++) { + data_f4[i] = normalize(data_f4[i]); + } + } + + float time = end(index); + rsDebug("fp_norm M ops", 10.f / time); +} + +static void test_sincos4(uint32_t index) { + start(); + + float total = 0; + // Do ~10 M ops + for (int ct=0; ct < 1000 * 10 / 4; ct++) { + for (int i=0; i < (1000); i++) { + data_f4[i] = sin(data_f4[i]) * cos(data_f4[i]); + } + } + + float time = end(index); + rsDebug("fp_sincos4 M ops", 10.f / time); +} + +static void test_sincos(uint32_t index) { + start(); + + float total = 0; + // Do ~10 M ops + for (int ct=0; ct < 1000 * 10; ct++) { + for (int i=0; i < (1000); i++) { + data_f1[i] = sin(data_f1[i]) * cos(data_f1[i]); + } + } + + float time = end(index); + rsDebug("fp_sincos M ops", 10.f / time); +} + +static void test_clamp(uint32_t index) { + start(); + + // Do ~100 M ops + for (int ct=0; ct < 1000 * 100; ct++) { + for (int i=0; i < (1000); i++) { + data_f1[i] = clamp(data_f1[i], -1.f, 1.f); + } + } + + float time = end(index); + rsDebug("fp_clamp M ops", 100.f / time); + + start(); + // Do ~100 M ops + for (ct=0; ct < 1000 * 100; ct++) { + for (int i=0; i < (1000); i++) { + if (data_f1[i] < -1.f) data_f1[i] = -1.f; + if (data_f1[i] > -1.f) data_f1[i] = 1.f; + } + } + + time = end(index); + rsDebug("fp_clamp ref M ops", 100.f / time); +} + +static void test_clamp4(uint32_t index) { + start(); + + float total = 0; + // Do ~100 M ops + for (int ct=0; ct < 1000 * 100 /4; ct++) { + for (int i=0; i < (1000); i++) { + data_f4[i] = clamp(data_f4[i], -1.f, 1.f); + } + } + + float time = end(index); + rsDebug("fp_clamp4 M ops", 100.f / time); +} + +void fp_mad_test(uint32_t index, int test_num) { + for (int x=0; x < 1025; x++) { + data_f1[x] = (x & 0xf) * 0.1f; + data_f4[x].x = (x & 0xf) * 0.1f; + data_f4[x].y = (x & 0xf0) * 0.1f; + data_f4[x].z = (x & 0x33) * 0.1f; + data_f4[x].w = (x & 0x77) * 0.1f; + } + + test_mad4(index); + test_mad(index); + + for (x=0; x < 1025; x++) { + data_f1[x] = (x & 0xf) * 0.1f + 1.f; + data_f4[x].x = (x & 0xf) * 0.1f + 1.f; + data_f4[x].y = (x & 0xf0) * 0.1f + 1.f; + data_f4[x].z = (x & 0x33) * 0.1f + 1.f; + data_f4[x].w = (x & 0x77) * 0.1f + 1.f; + } + + test_norm(index); + test_sincos4(index); + test_sincos(index); + test_clamp4(index); + test_clamp(index); + + // TODO Actually verify test result accuracy + rsDebug("fp_mad_test PASSED", 0); + rsSendToClientBlocking(RS_MSG_TEST_PASSED); +} + + diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs new file mode 100644 index 0000000..351a8a5 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -0,0 +1,63 @@ +#include "shared.rsh" + +#pragma rs export_func(primitives_test) + +// Testing primitive types +float floatTest = 1.99f; +double doubleTest = 2.05; +char charTest = -8; +short shortTest = -16; +int intTest = -32; +long longTest = 17179869184l; // 1 << 34 +long long longlongTest = 68719476736l; // 1 << 36 + +uchar ucharTest = 8; +ushort ushortTest = 16; +uint uintTest = 32; +ulong ulongTest = 4611686018427387904L; +int64_t int64_tTest = -17179869184l; // - 1 << 34 +uint64_t uint64_tTest = 117179869184l; + +static bool test_primitive_types(uint32_t index) { + bool failed = false; + start(); + + _RS_ASSERT(floatTest == 2.99f); + _RS_ASSERT(doubleTest == 3.05); + _RS_ASSERT(charTest == -16); + _RS_ASSERT(shortTest == -32); + _RS_ASSERT(intTest == -64); + _RS_ASSERT(longTest == 17179869185l); + _RS_ASSERT(longlongTest == 68719476735l); + + _RS_ASSERT(ucharTest == 8); + _RS_ASSERT(ushortTest == 16); + _RS_ASSERT(uintTest == 32); + _RS_ASSERT(ulongTest == 4611686018427387903L); + _RS_ASSERT(int64_tTest == -17179869184l); + _RS_ASSERT(uint64_tTest == 117179869185l); + + float time = end(index); + + if (failed) { + rsDebug("test_primitives FAILED", time); + } + else { + rsDebug("test_primitives PASSED", time); + } + + return failed; +} + +void primitives_test(uint32_t index, int test_num) { + bool failed = false; + failed |= test_primitive_types(index); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs new file mode 100644 index 0000000..b2d06fe --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs @@ -0,0 +1,107 @@ +// 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.test) + +#include "rs_graphics.rsh" + +float gDY; + +rs_font gFont; + +typedef struct ListAllocs_s { + rs_allocation text; + int result; +} ListAllocs; + +ListAllocs *gList; + +void init() { + gDY = 0.0f; +} + +int textPos = 0; + +int root(int launchID) { + + rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); + rsgClearDepth(1.0f); + + textPos -= (int)gDY*2; + gDY *= 0.95; + + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + rsgBindFont(gFont); + color(0.2, 0.2, 0.2, 0); + + rs_allocation listAlloc = rsGetAllocation(gList); + int allocSize = rsAllocationGetDimX(listAlloc); + + int width = rsgGetWidth(); + int height = rsgGetHeight(); + + int itemHeight = 80; + int totalItemHeight = itemHeight * allocSize; + + /* Prevent scrolling above the top of the list */ + int firstItem = height - totalItemHeight; + if (firstItem < 0) { + firstItem = 0; + } + + /* Prevent scrolling past the last line of the list */ + int lastItem = -1 * (totalItemHeight - height); + if (lastItem > 0) { + lastItem = 0; + } + + if (textPos > firstItem) { + textPos = firstItem; + } + else if (textPos < lastItem) { + textPos = lastItem; + } + + int currentYPos = itemHeight + textPos; + + for(int i = 0; i < allocSize; i ++) { + if(currentYPos - itemHeight > height) { + break; + } + + if(currentYPos > 0) { + switch(gList[i].result) { + case 1: /* Passed */ + rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f); + break; + case -1: /* Failed */ + rsgFontColor(0.9f, 0.5f, 0.5f, 1.0f); + break; + case 0: /* Still Testing */ + rsgFontColor(0.9f, 0.9f, 0.5f, 1.0f); + break; + default: /* Unknown */ + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + break; + } + rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0); + rsgDrawText(gList[i].text, 30, currentYPos - 32); + } + currentYPos += itemHeight; + } + + return 10; +} diff --git a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh new file mode 100644 index 0000000..21be9af --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh @@ -0,0 +1,38 @@ +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.test) + +typedef struct TestResult_s { + rs_allocation name; + bool pass; + float score; + int64_t time; +} TestResult; +//TestResult *g_results; + +static int64_t g_time; + +static void start(void) { + g_time = rsUptimeMillis(); +} + +static float end(uint32_t idx) { + int64_t t = rsUptimeMillis() - g_time; + //g_results[idx].time = t; + //rsDebug("test time", (int)t); + return ((float)t) / 1000.f; +} + +#define _RS_ASSERT(b) \ +do { \ + if (!(b)) { \ + failed = true; \ + rsDebug(#b " FAILED", 0); \ + } \ +\ +} while (0) + +/* These constants must match those in UnitTest.java */ +static const int RS_MSG_TEST_PASSED = 100; +static const int RS_MSG_TEST_FAILED = 101; + diff --git a/libs/rs/java/tests/src/com/android/rs/test/test_root.rs b/libs/rs/java/tests/src/com/android/rs/test/test_root.rs new file mode 100644 index 0000000..6dc83ba --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/test_root.rs @@ -0,0 +1,23 @@ +// Fountain test script +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.test) + +#pragma stateFragment(parent) + +#include "rs_graphics.rsh" + + +typedef struct TestResult { + rs_allocation name; + bool pass; + float score; +} TestResult_t; +TestResult_t *results; + +int root() { + + return 0; +} + + diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 5ae8d01..eb2942e 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -1,11 +1,14 @@ +ContextFinish { + handcodeApi + } ContextBindRootScript { param RsScript sampler } -ContextBindProgramFragmentStore { - param RsProgramFragmentStore pgm +ContextBindProgramStore { + param RsProgramStore pgm } ContextBindProgramFragment { @@ -20,6 +23,10 @@ ContextBindProgramRaster { param RsProgramRaster pgm } +ContextBindFont { + param RsFont pgm + } + ContextPause { } @@ -51,8 +58,13 @@ AssignName { param size_t len } -ObjDestroy { +GetName { param void *obj + param const char **name + } + +ObjDestroy { + param RsAsyncVoidPtr objPtr } ElementCreate { @@ -68,20 +80,28 @@ ElementCreate2 { param const RsElement * elements param const char ** names param const size_t * nameLengths + param const uint32_t * arraySize ret RsElement } -TypeBegin { - param RsElement type +ElementGetNativeData { + param RsElement elem + param uint32_t *elemData + param uint32_t elemDataSize } -TypeAdd { - param RsDimension dim - param size_t value +ElementGetSubElements { + param RsElement elem + param uint32_t *ids + param const char **names + param uint32_t dataSize } -TypeCreate { - ret RsType + +TypeGetNativeData { + param RsType type + param uint32_t * typeData + param uint32_t typeDataSize } AllocationCreateTyped { @@ -95,10 +115,16 @@ AllocationCreateSized { ret RsAllocation } +AllocationUpdateFromBitmap { + param RsAllocation alloc + param RsElement srcFmt + param const void * data + } + AllocationCreateBitmapRef { param RsType type - param void * bmpPtr - param void * callbackData + param RsAsyncVoidPtr bmpPtr + param RsAsyncVoidPtr callbackData param RsBitmapCallback_t callback ret RsAllocation } @@ -113,16 +139,6 @@ AllocationCreateFromBitmap { ret RsAllocation } -AllocationCreateFromBitmapBoxed { - param uint32_t width - param uint32_t height - param RsElement dstFmt - param RsElement srcFmt - param bool genMips - param const void * data - ret RsAllocation - } - AllocationUploadToTexture { param RsAllocation alloc @@ -153,6 +169,16 @@ Allocation1DSubData { togglePlay } +Allocation1DSubElementData { + param RsAllocation va + param uint32_t x + param const void *data + param uint32_t comp_offset + param uint32_t bytes + handcodeApi + togglePlay + } + Allocation2DSubData { param RsAllocation va param uint32_t xoff @@ -163,6 +189,15 @@ Allocation2DSubData { param uint32_t bytes } +Allocation2DSubElementData { + param RsAllocation va + param uint32_t x + param uint32_t y + param const void *data + param uint32_t element_offset + param uint32_t bytes + } + AllocationRead { param RsAllocation va param void * data @@ -224,6 +259,22 @@ Adapter2DSubData { param const void *data } +AllocationGetType { + param RsAllocation va + ret const void* + } + +AllocationResize1D { + param RsAllocation va + param uint32_t dimX + } + +AllocationResize2D { + param RsAllocation va + param uint32_t dimX + param uint32_t dimY + } + SamplerBegin { } @@ -232,6 +283,11 @@ SamplerSet { param RsSamplerValue value } +SamplerSet2 { + param RsSamplerParam p + param float value + } + SamplerCreate { ret RsSampler } @@ -248,13 +304,6 @@ ScriptBindAllocation { ScriptCBegin { } -ScriptSetClearColor { - param RsScript s - param float r - param float g - param float b - param float a - } ScriptSetTimeZone { param RsScript s @@ -262,43 +311,55 @@ ScriptSetTimeZone { param uint32_t length } -ScriptSetClearDepth { + +ScriptInvoke { param RsScript s - param float depth + param uint32_t slot } -ScriptSetClearStencil { +ScriptInvokeV { param RsScript s - param uint32_t stencil + param uint32_t slot + param const void * data + param uint32_t dataLen + handcodeApi + togglePlay } -ScriptSetType { - param RsType type +ScriptSetVarI { + param RsScript s param uint32_t slot - param bool isWritable - param const char * name + param int value } -ScriptSetInvoke { - param const char * name +ScriptSetVarJ { + param RsScript s param uint32_t slot + param int64_t value } -ScriptInvoke { +ScriptSetVarF { param RsScript s param uint32_t slot + param float value } -ScriptSetRoot { - param bool isRoot +ScriptSetVarD { + param RsScript s + param uint32_t slot + param double value } - - -ScriptCSetScript { - param void * codePtr +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 @@ -308,52 +369,41 @@ ScriptCCreate { ret RsScript } -ScriptCSetDefineF { - param const char* name - param float value - } - -ScriptCSetDefineI32 { - param const char* name - param int32_t value - } -ProgramFragmentStoreBegin { +ProgramStoreBegin { param RsElement in param RsElement out } -ProgramFragmentStoreColorMask { +ProgramStoreColorMask { param bool r param bool g param bool b param bool a } -ProgramFragmentStoreBlendFunc { +ProgramStoreBlendFunc { param RsBlendSrcFunc srcFunc param RsBlendDstFunc destFunc } -ProgramFragmentStoreDepthMask { +ProgramStoreDepthMask { param bool enable } -ProgramFragmentStoreDither { +ProgramStoreDither { param bool enable } -ProgramFragmentStoreDepthFunc { +ProgramStoreDepthFunc { param RsDepthFunc func } -ProgramFragmentStoreCreate { - ret RsProgramFragmentStore +ProgramStoreCreate { + ret RsProgramStore } ProgramRasterCreate { - param RsElement in - param RsElement out param bool pointSmooth param bool lineSmooth param bool pointSprite @@ -365,12 +415,11 @@ ProgramRasterSetLineWidth { param float lw } -ProgramRasterSetPointSize{ +ProgramRasterSetCullMode { param RsProgramRaster pr - param float ps + param RsCullMode mode } - ProgramBindConstants { param RsProgram vp param uint32_t slot @@ -391,12 +440,6 @@ ProgramBindSampler { } ProgramFragmentCreate { - param const uint32_t * params - param uint32_t paramLength - ret RsProgramFragment - } - -ProgramFragmentCreate2 { param const char * shaderText param uint32_t shaderLength param const uint32_t * params @@ -405,11 +448,6 @@ ProgramFragmentCreate2 { } ProgramVertexCreate { - param bool texMat - ret RsProgramVertex - } - -ProgramVertexCreate2 { param const char * shaderText param uint32_t shaderLength param const uint32_t * params @@ -417,66 +455,91 @@ ProgramVertexCreate2 { ret RsProgramVertex } -LightBegin { +FileA3DCreateFromAssetStream { + param const void * data + param size_t len + ret RsFile } -LightSetLocal { - param bool isLocal +FileOpen { + ret RsFile + param const char *name + param size_t len } -LightSetMonochromatic { - param bool isMono +FileA3DGetNumIndexEntries { + param int32_t * numEntries + param RsFile file } -LightCreate { - ret RsLight light +FileA3DGetIndexEntries { + param RsFileIndexEntry * fileEntries + param uint32_t numEntries + param RsFile fileA3D } +FileA3DGetEntryByIndex { + param uint32_t index + param RsFile file + ret RsObjectBase + } -LightSetPosition { - param RsLight light - param float x - param float y - param float z +FontCreateFromFile { + param const char *name + param uint32_t fontSize + param uint32_t dpi + ret RsFont } -LightSetColor { - param RsLight light - param float r - param float g - param float b +MeshCreate { + ret RsMesh + param uint32_t vtxCount + param uint32_t idxCount } -FileOpen { - ret RsFile - param const char *name - param size_t len +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 + } -SimpleMeshCreate { - ret RsSimpleMesh - param RsAllocation prim - param RsAllocation index - param RsAllocation *vtx - param uint32_t vtxCount - param uint32_t primType +MeshGetVertexBufferCount { + param RsMesh mesh + param int32_t *numVtx } +MeshGetIndexCount { + param RsMesh mesh + param int32_t *numIdx + } -SimpleMeshBindIndex { - param RsSimpleMesh mesh - param RsAllocation idx +MeshGetVertices { + param RsMesh mv + param RsAllocation *vtxData + param uint32_t vtxDataCount } -SimpleMeshBindPrimitive { - param RsSimpleMesh mesh - param RsAllocation prim +MeshGetIndices { + param RsMesh mv + param RsAllocation *va + param uint32_t *primType + param uint32_t idxDataCount } -SimpleMeshBindVertex { - param RsSimpleMesh mesh - param RsAllocation vtx - param uint32_t slot +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/rsAdapter.cpp b/libs/rs/rsAdapter.cpp index 0d31fac..ef69b75 100644 --- a/libs/rs/rsAdapter.cpp +++ b/libs/rs/rsAdapter.cpp @@ -15,7 +15,11 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif using namespace android; using namespace android::renderscript; @@ -70,6 +74,16 @@ void Adapter1D::data(const void *data) mAllocation.get()->getType()->getSizeBytes()); } +void Adapter1D::serialize(OStream *stream) const +{ + +} + +Adapter1D *Adapter1D::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} + namespace android { namespace renderscript { @@ -169,7 +183,6 @@ void Adapter2D::subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, co uint32_t eSize = mAllocation.get()->getType()->getElementSizeBytes(); uint32_t lineSize = eSize * w; - uint32_t destW = getDimX(); const uint8_t *src = static_cast<const uint8_t *>(data); for (uint32_t line=yoff; line < (yoff+h); line++) { @@ -185,6 +198,15 @@ void Adapter2D::data(const void *data) mAllocation.get()->getType()->getSizeBytes()); } +void Adapter2D::serialize(OStream *stream) const +{ + +} + +Adapter2D *Adapter2D::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} namespace android { diff --git a/libs/rs/rsAdapter.h b/libs/rs/rsAdapter.h index cb2872e..449e7ad 100644 --- a/libs/rs/rsAdapter.h +++ b/libs/rs/rsAdapter.h @@ -50,6 +50,10 @@ public: void subData(uint32_t xoff, uint32_t count, const void *data); void data(const void *data); + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ADAPTER_1D; } + static Adapter1D *createFromStream(Context *rsc, IStream *stream); + protected: ObjectBaseRef<Allocation> mAllocation; uint32_t mY; @@ -82,6 +86,10 @@ public: void data(const void *data); void subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data); + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ADAPTER_2D; } + static Adapter2D *createFromStream(Context *rsc, IStream *stream); + protected: ObjectBaseRef<Allocation> mAllocation; uint32_t mZ; diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 4e8278d..775fdf7 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -13,12 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" #include <GLES/gl.h> #include <GLES2/gl2.h> #include <GLES/glext.h> +#else +#include "rsContextHostStub.h" + +#include <OpenGL/gl.h> +#include <OpenGl/glext.h> +#endif + +#include "utils/StopWatch.h" using namespace android; using namespace android::renderscript; @@ -28,6 +36,9 @@ Allocation::Allocation(Context *rsc, const Type *type) : ObjectBase(rsc) init(rsc, type); mPtr = malloc(mType->getSizeBytes()); + if (mType->getElement()->getHasReferences()) { + memset(mPtr, 0, mType->getSizeBytes()); + } if (!mPtr) { LOGE("Allocation::Allocation, alloc failure"); } @@ -141,6 +152,8 @@ void Allocation::uploadToTexture(const Context *rsc) return; } + bool isFirstUpload = false; + if (!mTextureID) { glGenTextures(1, &mTextureID); @@ -153,6 +166,7 @@ void Allocation::uploadToTexture(const Context *rsc) mUploadDefered = true; return; } + isFirstUpload = true; } glBindTexture(GL_TEXTURE_2D, mTextureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -162,14 +176,23 @@ void Allocation::uploadToTexture(const Context *rsc) adapt.setLOD(lod+mTextureLOD); uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0)); - glTexImage2D(GL_TEXTURE_2D, lod, format, - adapt.getDimX(), adapt.getDimY(), - 0, format, type, ptr); + if(isFirstUpload) { + glTexImage2D(GL_TEXTURE_2D, lod, format, + adapt.getDimX(), adapt.getDimY(), + 0, format, type, ptr); + } else { + glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, + adapt.getDimX(), adapt.getDimY(), + format, type, ptr); + } } if (mTextureGenMipmap) { +#ifndef ANDROID_RS_BUILD_FOR_HOST glGenerateMipmap(GL_TEXTURE_2D); +#endif //ANDROID_RS_BUILD_FOR_HOST } + rsc->checkError("Allocation::uploadToTexture"); } void Allocation::deferedUploadToBufferObject(const Context *rsc) @@ -201,6 +224,7 @@ void Allocation::uploadToBufferObject(const Context *rsc) glBindBuffer(GL_ARRAY_BUFFER, mBufferID); glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); + rsc->checkError("Allocation::uploadToBufferObject"); } void Allocation::uploadCheck(const Context *rsc) @@ -217,13 +241,19 @@ void Allocation::uploadCheck(const Context *rsc) } -void Allocation::data(const void *data, uint32_t sizeBytes) +void Allocation::data(Context *rsc, const void *data, uint32_t sizeBytes) { uint32_t size = mType->getSizeBytes(); if (size != sizeBytes) { LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes); return; } + + if (mType->getElement()->getHasReferences()) { + incRefs(data, sizeBytes / mType->getElement()->getSizeBytes()); + decRefs(mPtr, sizeBytes / mType->getElement()->getSizeBytes()); + } + memcpy(mPtr, data, size); sendDirty(); mUploadDefered = true; @@ -234,7 +264,7 @@ void Allocation::read(void *data) memcpy(data, mPtr, mType->getSizeBytes()); } -void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) +void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); uint8_t * ptr = static_cast<uint8_t *>(mPtr); @@ -246,12 +276,18 @@ void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32 mType->dumpLOGV("type info"); return; } + + if (mType->getElement()->getHasReferences()) { + incRefs(data, count); + decRefs(ptr, count); + } + memcpy(ptr, data, size); sendDirty(); mUploadDefered = true; } -void Allocation::subData(uint32_t xoff, uint32_t yoff, +void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { uint32_t eSize = mType->getElementSizeBytes(); @@ -268,7 +304,10 @@ void Allocation::subData(uint32_t xoff, uint32_t yoff, } for (uint32_t line=yoff; line < (yoff+h); line++) { - uint8_t * ptr = static_cast<uint8_t *>(mPtr); + if (mType->getElement()->getHasReferences()) { + incRefs(src, w); + decRefs(dst, w); + } memcpy(dst, src, lineSize); src += lineSize; dst += destW * eSize; @@ -277,14 +316,96 @@ void Allocation::subData(uint32_t xoff, uint32_t yoff, mUploadDefered = true; } -void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff, +void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { } +void Allocation::subElementData(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; + + if (cIdx >= mType->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()) { + 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); + + if (sizeBytes != e->getSizeBytes()) { + LOGE("Error Allocation::subElementData data size %i does not match field size %i.", 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; +} + +void Allocation::subElementData(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()); + + if (x >= mType->getDimX()) { + 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()) { + 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()) { + 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); + + if (sizeBytes != e->getSizeBytes()) { + LOGE("Error Allocation::subElementData data size %i does not match field size %i.", 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; +} + void Allocation::addProgramToDirty(const Program *p) { - mToDirtyList.add(p); + mToDirtyList.push(p); } void Allocation::removeProgramToDirty(const Program *p) @@ -316,6 +437,61 @@ void Allocation::dumpLOGV(const char *prefix) const } +void Allocation::serialize(OStream *stream) const +{ + // Need to identify ourselves + stream->addU32((uint32_t)getClassId()); + + String8 name(getName()); + stream->addString(&name); + + // First thing we need to serialize is the type object since it will be needed + // to initialize the class + mType->serialize(stream); + + uint32_t dataSize = mType->getSizeBytes(); + // Write how much data we are storing + stream->addU32(dataSize); + // Now write the data + stream->addByteArray(mPtr, dataSize); +} + +Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) +{ + // First make sure we are reading the correct object + RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); + if(classID != RS_A3D_CLASS_ID_ALLOCATION) { + LOGE("allocation loading skipped due to invalid class id\n"); + return NULL; + } + + String8 name; + stream->loadString(&name); + + Type *type = Type::createFromStream(rsc, stream); + if(!type) { + return NULL; + } + type->compute(); + + // Number of bytes we wrote out for this allocation + uint32_t dataSize = stream->loadU32(); + if(dataSize != type->getSizeBytes()) { + LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n"); + delete type; + return NULL; + } + + Allocation *alloc = new Allocation(rsc, type); + alloc->setName(name.string(), name.size()); + + // Read in all of our allocation data + alloc->data(rsc, stream->getPtr() + stream->getPos(), dataSize); + stream->reset(stream->getPos() + dataSize); + + return alloc; +} + void Allocation::sendDirty() const { for (size_t ct=0; ct < mToDirtyList.size(); ct++) { @@ -323,6 +499,65 @@ void Allocation::sendDirty() const } } +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(); + uint32_t stride = e->getSizeBytes(); + + p += stride * startOff; + while (ct > 0) { + e->incRefs(p); + ct --; + p += stride; + } +} + +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(); + uint32_t stride = e->getSizeBytes(); + + p += stride * startOff; + while (ct > 0) { + e->decRefs(p); + ct --; + p += stride; + } +} + +void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len) +{ +} + +void Allocation::resize1D(Context *rsc, uint32_t dimX) +{ + Type *t = mType->cloneAndResize1D(rsc, dimX); + + uint32_t oldDimX = mType->getDimX(); + if (dimX == oldDimX) { + return; + } + + if (dimX < oldDimX) { + decRefs(mPtr, 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); +} + +void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) +{ + LOGE("not implemented"); +} + ///////////////// // @@ -495,7 +730,7 @@ static ElementConverter_t pickConverter(const Element *dst, const Element *src) if (srcGLType == GL_UNSIGNED_BYTE && srcGLFmt == GL_RGB && dstGLType == GL_UNSIGNED_SHORT_5_6_5 && - dstGLType == GL_RGB) { + dstGLFmt == GL_RGB) { return elementConverter_888_to_565; } @@ -503,15 +738,21 @@ static ElementConverter_t pickConverter(const Element *dst, const Element *src) if (srcGLType == GL_UNSIGNED_BYTE && srcGLFmt == GL_RGBA && dstGLType == GL_UNSIGNED_SHORT_5_6_5 && - dstGLType == GL_RGB) { + dstGLFmt == GL_RGB) { return elementConverter_8888_to_565; } LOGE("pickConverter, unsuported combo, src %p, dst %p", src, dst); + LOGE("pickConverter, srcGLType = %x, srcGLFmt = %x", srcGLType, srcGLFmt); + LOGE("pickConverter, dstGLType = %x, dstGLFmt = %x", dstGLType, dstGLFmt); + src->dumpLOGV("SRC "); + dst->dumpLOGV("DST "); return 0; } +#ifndef ANDROID_RS_BUILD_FOR_HOST + RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype, void *bmp, void *callbackData, RsBitmapCallback_t callback) { @@ -521,22 +762,41 @@ RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype, return alloc; } +void rsi_AllocationUpdateFromBitmap(Context *rsc, RsAllocation va, RsElement _src, const void *data) +{ + Allocation *texAlloc = static_cast<Allocation *>(va); + const Element *src = static_cast<const Element *>(_src); + const Element *dst = texAlloc->getType()->getElement(); + uint32_t w = texAlloc->getType()->getDimX(); + uint32_t h = texAlloc->getType()->getDimY(); + bool genMips = texAlloc->getType()->getDimLOD(); + + ElementConverter_t cvt = pickConverter(dst, src); + if (cvt) { + cvt(texAlloc->getPtr(), data, w * h); + if (genMips) { + Adapter2D adapt(rsc, texAlloc); + Adapter2D adapt2(rsc, texAlloc); + for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { + adapt.setLOD(lod); + adapt2.setLOD(lod + 1); + mip(adapt2, adapt); + } + } + } else { + rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format"); + } +} + RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data) { const Element *src = static_cast<const Element *>(_src); const Element *dst = static_cast<const Element *>(_dst); - // Check for pow2 on pre es 2.0 versions. - rsAssert(rsc->checkVersion2_0() || (!(w & (w-1)) && !(h & (h-1)))); - - //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips); - rsi_TypeBegin(rsc, _dst); - rsi_TypeAdd(rsc, RS_DIMENSION_X, w); - rsi_TypeAdd(rsc, RS_DIMENSION_Y, h); - if (genMips) { - rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1); - } - RsType type = rsi_TypeCreate(rsc); + //LOGE("%p rsi_AllocationCreateFromBitmap %i %i %i", rsc, w, h, genMips); + RsDimension dims[] = {RS_DIMENSION_X, RS_DIMENSION_Y, RS_DIMENSION_LOD}; + uint32_t dimValues[] = {w, h, genMips}; + RsType type = rsaTypeCreate(rsc, _dst, 3, dims, dimValues); RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type); Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); @@ -546,16 +806,19 @@ RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h } ElementConverter_t cvt = pickConverter(dst, src); - cvt(texAlloc->getPtr(), data, w * h); - - if (genMips) { - Adapter2D adapt(rsc, texAlloc); - Adapter2D adapt2(rsc, texAlloc); - for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { - adapt.setLOD(lod); - adapt2.setLOD(lod + 1); - mip(adapt2, adapt); + if (cvt) { + cvt(texAlloc->getPtr(), data, w * h); + if (genMips) { + Adapter2D adapt(rsc, texAlloc); + Adapter2D adapt2(rsc, texAlloc); + for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { + adapt.setLOD(lod); + adapt2.setLOD(lod + 1); + mip(adapt2, adapt); + } } + } else { + rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format"); } return texAlloc; @@ -592,19 +855,31 @@ RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint3 void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->data(data, sizeBytes); + a->data(rsc, data, sizeBytes); } void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subData(xoff, count, data, sizeBytes); + a->subData(rsc, xoff, count, data, sizeBytes); +} + +void rsi_Allocation2DSubElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, const void *data, uint32_t eoff, uint32_t sizeBytes) +{ + Allocation *a = static_cast<Allocation *>(va); + a->subElementData(rsc, x, y, data, eoff, sizeBytes); +} + +void rsi_Allocation1DSubElementData(Context *rsc, RsAllocation va, uint32_t x, const void *data, uint32_t eoff, uint32_t sizeBytes) +{ + Allocation *a = static_cast<Allocation *>(va); + a->subElementData(rsc, x, data, eoff, sizeBytes); } void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { Allocation *a = static_cast<Allocation *>(va); - a->subData(xoff, yoff, w, h, data, sizeBytes); + a->subData(rsc, xoff, yoff, w, h, data, sizeBytes); } void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) @@ -613,6 +888,27 @@ void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) a->read(data); } +void rsi_AllocationResize1D(Context *rsc, RsAllocation va, uint32_t dimX) +{ + Allocation *a = static_cast<Allocation *>(va); + a->resize1D(rsc, dimX); +} + +void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32_t dimY) +{ + Allocation *a = static_cast<Allocation *>(va); + a->resize2D(rsc, dimX, dimY); +} + +const void* rsi_AllocationGetType(Context *rsc, RsAllocation va) +{ + Allocation *a = static_cast<Allocation *>(va); + a->getType()->incUserRef(); + + return a->getType(); +} + +#endif //ANDROID_RS_BUILD_FOR_HOST } } diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index 516f8b7..12cf832 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -30,8 +30,6 @@ class Allocation : public ObjectBase // The graphics equilivent of malloc. The allocation contains a structure of elements. public: - // By policy this allocation will hold a pointer to the type - // but will not destroy it on destruction. Allocation(Context *rsc, const Type *); Allocation(Context *rsc, const Type *, void *bmp, void *callbackData, RsBitmapCallback_t callback); @@ -55,14 +53,23 @@ public: 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 data(const void *data, uint32_t sizeBytes); - void subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes); - void subData(uint32_t xoff, uint32_t yoff, + void resize1D(Context *rsc, uint32_t dimX); + void resize2D(Context *rsc, uint32_t dimX, uint32_t dimY); + + void data(Context *rsc, const void *data, uint32_t sizeBytes); + void subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes); + void subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes); - void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff, + void subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); + void subElementData(Context *rsc, uint32_t x, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + void subElementData(Context *rsc, uint32_t x, uint32_t y, + const void *data, uint32_t elementOff, uint32_t sizeBytes); + void read(void *data); void enableGLVertexBuffers() const; @@ -72,12 +79,22 @@ public: void removeProgramToDirty(const Program *); virtual void dumpLOGV(const char *prefix) const; + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ALLOCATION; } + static Allocation *createFromStream(Context *rsc, IStream *stream); virtual void uploadCheck(const Context *rsc); -protected: + bool getIsTexture() const {return mIsTexture;} + bool getIsBufferObject() const {return mIsVertexBuffer;} + + 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; + bool getHasGraphicsMipmaps() const {return mTextureGenMipmap;} +protected: ObjectBaseRef<const Type> mType; void * mPtr; diff --git a/libs/rs/rsAnimation.cpp b/libs/rs/rsAnimation.cpp new file mode 100644 index 0000000..6200715 --- /dev/null +++ b/libs/rs/rsAnimation.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsAnimation.h" + + +using namespace android; +using namespace android::renderscript; + +void Animation::serialize(OStream *stream) const +{ + +} + +Animation *Animation::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} + +/* +Animation::Animation(Context *rsc) : ObjectBase(rsc) +{ + mAllocFile = __FILE__; + mAllocLine = __LINE__; + + mValuesInput = NULL; + mValuesOutput = NULL; + mValueCount = 0; + mInterpolation = RS_ANIMATION_INTERPOLATION_STEP; + mEdgePre = RS_ANIMATION_EDGE_UNDEFINED; + mEdgePost = RS_ANIMATION_EDGE_UNDEFINED; + mInputMin = 0; + mInputMax = 0; +} + +Animation * Animation::create(Context *rsc, + const float *inValues, const float *outValues, + uint32_t valueCount, RsAnimationInterpolation interp, + RsAnimationEdge pre, RsAnimationEdge post) +{ + if (valueCount < 2) { + rsc->setError(RS_ERROR_BAD_VALUE, "Animations require more than 2 values."); + return NULL; + } + Animation *a = new Animation(rsc); + if (!a) { + rsc->setError(RS_ERROR_OUT_OF_MEMORY); + return NULL; + } + + float *vin = (float *)malloc(valueCount * sizeof(float)); + float *vout = (float *)malloc(valueCount * sizeof(float)); + a->mValuesInput = vin; + a->mValuesOutput = vout; + if (a->mValuesInput == NULL || a->mValuesOutput == NULL) { + delete a; + rsc->setError(RS_ERROR_OUT_OF_MEMORY); + return NULL; + } + + a->mEdgePre = pre; + a->mEdgePost = post; + a->mInterpolation = interp; + a->mValueCount = valueCount; + + memcpy(vin, inValues, valueCount * sizeof(float)); + memcpy(vout, outValues, valueCount * sizeof(float)); + a->mInputMin = inValues[0]; + a->mInputMax = inValues[0]; + + bool needSort = false; + for (uint32_t ct=1; ct < valueCount; ct++) { + if (a->mInputMin > vin[ct]) { + needSort = true; + a->mInputMin = vin[ct]; + } + if (a->mInputMax < vin[ct]) { + a->mInputMax = vin[ct]; + } else { + needSort = true; + } + } + + while (1) { + bool changed = false; + for (uint32_t ct=1; ct < valueCount; ct++) { + if (vin[ct-1] > vin[ct]) { + float t = vin[ct-1]; + vin[ct-1] = vin[ct]; + vin[ct] = t; + t = vout[ct-1]; + vout[ct-1] = vout[ct]; + vout[ct] = t; + changed = true; + } + } + if (!changed) break; + } + + return a; +} +*/ + + +///////////////////////////////////////// +// + +namespace android { +namespace renderscript { + +RsAnimation rsi_AnimationCreate(Context *rsc, + const float *inValues, + const float *outValues, + uint32_t valueCount, + RsAnimationInterpolation interp, + RsAnimationEdge pre, + RsAnimationEdge post) +{ + //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize); + Animation *a = NULL;//Animation::create(rsc, inValues, outValues, valueCount, interp, pre, post); + if (a != NULL) { + a->incUserRef(); + } + return (RsAnimation)a; +} + + +} +} + diff --git a/libs/rs/rsAnimation.h b/libs/rs/rsAnimation.h new file mode 100644 index 0000000..340314e --- /dev/null +++ b/libs/rs/rsAnimation.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_ANIMATION_H +#define ANDROID_RS_ANIMATION_H + +#include "rsUtils.h" +#include "rsObjectBase.h" + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + + +class Animation : public ObjectBase +{ +public: + ~Animation(); + + static Animation * create(Context *rsc, + const float *inValues, const float *outValues, + uint32_t valueCount, RsAnimationInterpolation, + RsAnimationEdge pre, RsAnimationEdge post); + + float eval(float) const; + + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ANIMATION; } + static Animation *createFromStream(Context *rsc, IStream *stream); + +protected: + Animation(Context *rsc); + + + + float evalInRange(float) const; + + + + const float *mValuesInput; + const float *mValuesOutput; + uint32_t mValueCount; + RsAnimationInterpolation mInterpolation; + RsAnimationEdge mEdgePre; + RsAnimationEdge mEdgePost; + + // derived + float mInputMin; + float mInputMax; +}; + + + + +} +} +#endif //ANDROID_STRUCTURED_ELEMENT_H + diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 15a56f7..f51b23e 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -16,7 +16,11 @@ #include "rsComponent.h" +#ifndef ANDROID_RS_BUILD_FOR_HOST #include <GLES/gl.h> +#else +#include <OpenGL/gl.h> +#endif using namespace android; using namespace android::renderscript; @@ -91,6 +95,26 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) mNormalized = true; rsAssert(mKind == RS_KIND_PIXEL_RGBA); return; + + case RS_TYPE_MATRIX_4X4: + mTypeBits = 16 * 32; + rsAssert(mVectorSize == 1); + rsAssert(mNormalized == false); + rsAssert(mKind == RS_KIND_USER); + break; + case RS_TYPE_MATRIX_3X3: + mTypeBits = 9 * 32; + rsAssert(mVectorSize == 1); + rsAssert(mNormalized == false); + rsAssert(mKind == RS_KIND_USER); + break; + case RS_TYPE_MATRIX_2X2: + mTypeBits = 4 * 32; + rsAssert(mVectorSize == 1); + rsAssert(mNormalized == false); + rsAssert(mKind == RS_KIND_USER); + break; + case RS_TYPE_ELEMENT: case RS_TYPE_TYPE: case RS_TYPE_ALLOCATION: @@ -148,11 +172,19 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) case RS_TYPE_UNSIGNED_64: mTypeBits = 64; break; + + case RS_TYPE_BOOLEAN: + mTypeBits = 8; + break; } mBits = mTypeBits * mVectorSize; } +bool Component::isReference() const +{ + return (mType >= RS_TYPE_ELEMENT); +} @@ -188,82 +220,6 @@ uint32_t Component::getGLFormat() const return 0; } -static const char * gCTypeStrings[] = { - 0, - 0,//"F16", - "float", - "double", - "char", - "short", - "int", - 0,//"S64", - "char",//U8", - "short",//U16", - "int",//U32", - 0,//"U64", - 0,//"UP_565", - 0,//"UP_5551", - 0,//"UP_4444", - 0,//"ELEMENT", - 0,//"TYPE", - 0,//"ALLOCATION", - 0,//"SAMPLER", - 0,//"SCRIPT", - 0,//"MESH", - 0,//"PROGRAM_FRAGMENT", - 0,//"PROGRAM_VERTEX", - 0,//"PROGRAM_RASTER", - 0,//"PROGRAM_STORE", -}; - -static const char * gCVecTypeStrings[] = { - 0, - 0,//"F16", - "vecF32", - "vecF64", - "vecI8", - "vecI16", - "vecI32", - 0,//"S64", - "vecU8",//U8", - "vecU16",//U16", - "vecU32",//U32", - 0,//"U64", - 0,//"UP_565", - 0,//"UP_5551", - 0,//"UP_4444", - 0,//"ELEMENT", - 0,//"TYPE", - 0,//"ALLOCATION", - 0,//"SAMPLER", - 0,//"SCRIPT", - 0,//"MESH", - 0,//"PROGRAM_FRAGMENT", - 0,//"PROGRAM_VERTEX", - 0,//"PROGRAM_RASTER", - 0,//"PROGRAM_STORE", -}; - -String8 Component::getCType() const -{ - char buf[64]; - if (mVectorSize == 1) { - return String8(gCTypeStrings[mType]); - } - - // Yuck, acc WAR - // Appears to have problems packing chars - if (mVectorSize == 4 && mType == RS_TYPE_UNSIGNED_8) { - return String8("int"); - } - - - String8 s(gCVecTypeStrings[mType]); - sprintf(buf, "_%i_t", mVectorSize); - s.append(buf); - return s; -} - String8 Component::getGLSLType() const { if (mType == RS_TYPE_SIGNED_32) { @@ -282,10 +238,19 @@ String8 Component::getGLSLType() const case 4: return String8("vec4"); } } + if ((mType == RS_TYPE_MATRIX_4X4) && (mVectorSize == 1)) { + return String8("mat4"); + } + if ((mType == RS_TYPE_MATRIX_3X3) && (mVectorSize == 1)) { + return String8("mat3"); + } + if ((mType == RS_TYPE_MATRIX_2X2) && (mVectorSize == 1)) { + return String8("mat2"); + } return String8(); } -static const char * gTypeStrings[] = { +static const char * gTypeBasicStrings[] = { "NONE", "F16", "F32", @@ -298,9 +263,16 @@ static const char * gTypeStrings[] = { "U16", "U32", "U64", + "BOOLEAN", "UP_565", "UP_5551", "UP_4444", + "MATRIX_4X4", + "MATRIX_3X3", + "MATRIX_2X2", +}; + +static const char * gTypeObjStrings[] = { "ELEMENT", "TYPE", "ALLOCATION", @@ -330,8 +302,34 @@ static const char * gKindStrings[] = { void Component::dumpLOGV(const char *prefix) const { - LOGV("%s Component: %s, %s, vectorSize=%i, bits=%i", - prefix, gTypeStrings[mType], gKindStrings[mKind], mVectorSize, mBits); + if (mType >= RS_TYPE_ELEMENT) { + LOGV("%s Component: %s, %s, vectorSize=%i, bits=%i", + prefix, gTypeObjStrings[mType - RS_TYPE_ELEMENT], gKindStrings[mKind], mVectorSize, mBits); + } else { + LOGV("%s Component: %s, %s, vectorSize=%i, bits=%i", + prefix, gTypeBasicStrings[mType], gKindStrings[mKind], mVectorSize, mBits); + } +} + +void Component::serialize(OStream *stream) const +{ + stream->addU8((uint8_t)mType); + stream->addU8((uint8_t)mKind); + stream->addU8((uint8_t)(mNormalized ? 1 : 0)); + stream->addU32(mVectorSize); } +void Component::loadFromStream(IStream *stream) +{ + mType = (RsDataType)stream->loadU8(); + mKind = (RsDataKind)stream->loadU8(); + uint8_t temp = stream->loadU8(); + mNormalized = temp != 0; + mVectorSize = stream->loadU32(); + + set(mType, mKind, mNormalized, mVectorSize); +} + + + diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h index 71de324..a775051 100644 --- a/libs/rs/rsComponent.h +++ b/libs/rs/rsComponent.h @@ -35,7 +35,6 @@ public: uint32_t getGLType() const; uint32_t getGLFormat() const; - String8 getCType() const; String8 getGLSLType() const; void dumpLOGV(const char *prefix) const; @@ -48,6 +47,12 @@ public: bool getIsSigned() const {return mIsSigned;} uint32_t getBits() const {return mBits;} + // Helpers for reading / writing this class out + void serialize(OStream *stream) const; + void loadFromStream(IStream *stream); + + bool isReference() const; + protected: RsDataType mType; RsDataKind mKind; diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 596f533..4dd074e 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -18,11 +18,13 @@ #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> +#include <sched.h> #include <cutils/properties.h> @@ -32,6 +34,8 @@ #include <GLES2/gl2ext.h> #include <cutils/sched_policy.h> +#include <sys/syscall.h> +#include <string.h> using namespace android; using namespace android::renderscript; @@ -53,8 +57,61 @@ static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { } } -void Context::initEGL(bool useGL2) +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); + } + } +} + + +void Context::initGLThread() { + pthread_mutex_lock(&gInitMutex); + LOGV("initGLThread start %p", this); + mEGL.mNumConfigs = -1; EGLint configAttribs[128]; EGLint *configAttribsPtr = configAttribs; @@ -66,15 +123,13 @@ void Context::initEGL(bool useGL2) configAttribsPtr[1] = EGL_WINDOW_BIT; configAttribsPtr += 2; - if (useGL2) { - configAttribsPtr[0] = EGL_RENDERABLE_TYPE; - configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; - configAttribsPtr += 2; - } + configAttribsPtr[0] = EGL_RENDERABLE_TYPE; + configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; + configAttribsPtr += 2; - if (mUseDepth) { + if (mUserSurfaceConfig.depthMin > 0) { configAttribsPtr[0] = EGL_DEPTH_SIZE; - configAttribsPtr[1] = 16; + configAttribsPtr[1] = mUserSurfaceConfig.depthMin; configAttribsPtr += 2; } @@ -87,36 +142,101 @@ void Context::initEGL(bool useGL2) configAttribsPtr[0] = EGL_NONE; rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint)))); - LOGV("initEGL start"); + LOGV("%p initEGL start", this); mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); checkEglError("eglGetDisplay"); eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion); checkEglError("eglInitialize"); - status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig); - if (err) { - LOGE("couldn't find an EGLConfig matching the screen format\n"); +#if 1 + PixelFormat pf = PIXEL_FORMAT_RGBA_8888; + if (mUserSurfaceConfig.alphaMin == 0) { + pf = PIXEL_FORMAT_RGBX_8888; } - //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs); - - if (useGL2) { - mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, context_attribs2); - } else { - mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL); + 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) { - LOGE("eglCreateContext returned EGL_NO_CONTEXT"); + LOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", this); } 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"); + } + + EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurfaceDefault, mEGL.mSurfaceDefault, mEGL.mContext); + checkEglError("eglMakeCurrent", ret); + + 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"); + } 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.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); } void Context::deinitEGL() { - LOGV("deinitEGL"); - setSurface(0, 0, NULL); + LOGV("%p, deinitEGL", this); + + eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEGL.mContext); eglDestroyContext(mEGL.mDisplay, mEGL.mContext); checkEglError("eglDestroyContext"); @@ -127,19 +247,21 @@ void Context::deinitEGL() } -uint32_t Context::runScript(Script *s, uint32_t launchID) +uint32_t Context::runScript(Script *s) { ObjectBaseRef<ProgramFragment> frag(mFragment); ObjectBaseRef<ProgramVertex> vtx(mVertex); - ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore); + ObjectBaseRef<ProgramStore> store(mFragmentStore); ObjectBaseRef<ProgramRaster> raster(mRaster); + ObjectBaseRef<Font> font(mFont); - uint32_t ret = s->run(this, launchID); + uint32_t ret = s->run(this); mFragment.set(frag); mVertex.set(vtx); mFragmentStore.set(store); mRaster.set(raster); + mFont.set(font); return ret; } @@ -147,42 +269,19 @@ void Context::checkError(const char *msg) const { GLenum err = glGetError(); if (err != GL_NO_ERROR) { - LOGE("GL Error, 0x%x, from %s", err, msg); + LOGE("%p, GL Error, 0x%x, from %s", this, err, msg); } } uint32_t Context::runRootScript() { - timerSet(RS_TIMER_CLEAR_SWAP); - rsAssert(mRootScript->mEnviroment.mIsRoot); - - eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); - eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); - glViewport(0, 0, mEGL.mWidth, mEGL.mHeight); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glClearColor(mRootScript->mEnviroment.mClearColor[0], - mRootScript->mEnviroment.mClearColor[1], - mRootScript->mEnviroment.mClearColor[2], - mRootScript->mEnviroment.mClearColor[3]); - if (mUseDepth) { - glDepthMask(GL_TRUE); - glClearDepthf(mRootScript->mEnviroment.mClearDepth); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } else { - glClear(GL_COLOR_BUFFER_BIT); - } + glViewport(0, 0, mWidth, mHeight); timerSet(RS_TIMER_SCRIPT); mStateFragmentStore.mLast.clear(); - uint32_t ret = runScript(mRootScript.get(), 0); + uint32_t ret = runScript(mRootScript.get()); checkError("runRootScript"); - if (mError != RS_ERROR_NONE) { - // If we have an error condition we stop rendering until - // somthing changes that might fix it. - ret = 0; - } return ret; } @@ -206,6 +305,9 @@ void Context::timerInit() mTimeFrame = mTimeLast; mTimeLastFrame = mTimeLast; mTimerActive = RS_TIMER_INTERNAL; + mAverageFPSFrameCount = 0; + mAverageFPSStartTime = mTimeLast; + mAverageFPS = 0; timerReset(); } @@ -213,6 +315,16 @@ void Context::timerFrame() { mTimeLastFrame = mTimeFrame; mTimeFrame = getTime(); + // Update average fps + const uint64_t averageFramerateInterval = 1000 * 1000000; + mAverageFPSFrameCount ++; + uint64_t inverval = mTimeFrame - mAverageFPSStartTime; + if(inverval >= averageFramerateInterval) { + inverval = inverval / 1000000; + mAverageFPS = (mAverageFPSFrameCount * 1000) / inverval; + mAverageFPSFrameCount = 0; + mAverageFPSStartTime = mTimeFrame; + } } void Context::timerSet(Timers tm) @@ -236,37 +348,34 @@ void Context::timerPrint() if (props.mLogTimes) { - LOGV("RS: Frame (%i), Script %2.1f (%i), Clear & Swap %2.1f (%i), Idle %2.1f (%lli), Internal %2.1f (%lli)", + LOGV("RS: Frame (%i), Script %2.1f (%i), Clear & Swap %2.1f (%i), Idle %2.1f (%lli), Internal %2.1f (%lli), Avg fps: %u", mTimeMSLastFrame, 100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimeMSLastScript, 100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimeMSLastSwap, 100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000, - 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000); + 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000, + mAverageFPS); } } bool Context::setupCheck() { - if (checkVersion2_0()) { - 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); - - } else { - mFragmentStore->setupGL(this, &mStateFragmentStore); - mFragment->setupGL(this, &mStateFragment); - mRaster->setupGL(this, &mStateRaster); - mVertex->setupGL(this, &mStateVertex); + 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); return true; } +void Context::setupProgramStore() { + mFragmentStore->setupGL2(this, &mStateFragmentStore); +} + static bool getProp(const char *str) { char buf[PROPERTY_VALUE_MAX]; @@ -274,6 +383,24 @@ static bool getProp(const char *str) return 0 != strcmp(buf, "0"); } +void Context::displayDebugStats() +{ + char buffer[128]; + sprintf(buffer, "Avg fps %u, Frame %i ms, Script %i ms", mAverageFPS, mTimeMSLastFrame, mTimeMSLastScript); + float oldR, oldG, oldB, oldA; + mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA); + uint32_t bufferLen = strlen(buffer); + + float shadowCol = 0.1f; + mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f); + mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 6); + + mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f); + mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 7); + + mStateFont.setFontColor(oldR, oldG, oldB, oldA); +} + void * Context::threadProc(void *vrsc) { Context *rsc = static_cast<Context *>(vrsc); @@ -286,28 +413,36 @@ void * Context::threadProc(void *vrsc) 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"); - ScriptTLSStruct *tlsStruct = new ScriptTLSStruct; - if (!tlsStruct) { + rsc->mTlsStruct = new ScriptTLSStruct; + if (!rsc->mTlsStruct) { LOGE("Error allocating tls storage"); return NULL; } - tlsStruct->mContext = rsc; - tlsStruct->mScript = NULL; - int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct); + rsc->mTlsStruct->mContext = rsc; + rsc->mTlsStruct->mScript = NULL; + int status = pthread_setspecific(rsc->gThreadTLSKey, rsc->mTlsStruct); if (status) { LOGE("pthread_setspecific %i", status); } + rsc->initGLThread(); + + rsc->mScriptC.init(rsc); if (rsc->mIsGraphicsContext) { - rsc->mStateRaster.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); + rsc->mStateRaster.init(rsc); rsc->setRaster(NULL); - rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); + rsc->mStateVertex.init(rsc); rsc->setVertex(NULL); - rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); + rsc->mStateFragment.init(rsc); rsc->setFragment(NULL); - rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight); + rsc->mStateFragmentStore.init(rsc); rsc->setFragmentStore(NULL); + rsc->mStateFont.init(rsc); + rsc->setFont(NULL); rsc->mStateVertexArray.init(rsc); } @@ -321,6 +456,11 @@ void * Context::threadProc(void *vrsc) 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); @@ -329,9 +469,6 @@ void * Context::threadProc(void *vrsc) rsc->timerPrint(); rsc->timerReset(); } - if (rsc->mObjDestroy.mNeedToEmpty) { - rsc->objDestroyOOBRun(); - } if (rsc->mThreadPriority > 0 && targetTime) { int32_t t = (targetTime - (int32_t)(rsc->mTimeMSLastScript + rsc->mTimeMSLastSwap)) * 1000; if (t > 0) { @@ -340,33 +477,85 @@ void * Context::threadProc(void *vrsc) } } - LOGV("RS Thread exiting"); + LOGV("%p, RS Thread exiting", rsc); if (rsc->mIsGraphicsContext) { rsc->mRaster.clear(); rsc->mFragment.clear(); rsc->mVertex.clear(); rsc->mFragmentStore.clear(); + rsc->mFont.clear(); rsc->mRootScript.clear(); rsc->mStateRaster.deinit(rsc); rsc->mStateVertex.deinit(rsc); rsc->mStateFragment.deinit(rsc); rsc->mStateFragmentStore.deinit(rsc); + rsc->mStateFont.deinit(rsc); } ObjectBase::zeroAllUserRef(rsc); - rsc->mObjDestroy.mNeedToEmpty = true; - rsc->objDestroyOOBRun(); - if (rsc->mIsGraphicsContext) { pthread_mutex_lock(&gInitMutex); rsc->deinitEGL(); pthread_mutex_unlock(&gInitMutex); } + delete rsc->mTlsStruct; - LOGV("RS Thread exited"); + LOGV("%p, RS Thread exited", rsc); return NULL; } +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->mRunning) { + 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 exiting %p idx=%i", rsc, idx); + return NULL; +} + +void Context::launchThreads(WorkerCallback_t cbk, void *data) +{ + mWorkers.mLaunchData = data; + mWorkers.mLaunchCallback = cbk; + mWorkers.mRunningCount = (int)mWorkers.mCount; + for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { + mWorkers.mLaunchSignals[ct].set(); + } + while(mWorkers.mRunningCount) { + mWorkers.mCompleteSignal.wait(); + } +} + void Context::setPriority(int32_t p) { // Note: If we put this in the proper "background" policy @@ -383,11 +572,14 @@ void Context::setPriority(int32_t p) // success; reset the priority as well } #else - setpriority(PRIO_PROCESS, mNativeThreadId, p); + setpriority(PRIO_PROCESS, mNativeThreadId, p); + for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { + setpriority(PRIO_PROCESS, mWorkers.mNativeThreadId[ct], p); + } #endif } -Context::Context(Device *dev, bool isGraphics, bool useDepth) +Context::Context(Device *dev, const RsSurfaceConfig *sc) { pthread_mutex_lock(&gInitMutex); @@ -395,15 +587,19 @@ Context::Context(Device *dev, bool isGraphics, bool useDepth) mDev = dev; mRunning = false; mExit = false; - mUseDepth = useDepth; mPaused = false; mObjHead = NULL; mError = RS_ERROR_NONE; mErrorMsg = NULL; + if (sc) { + mUserSurfaceConfig = *sc; + } else { + memset(&mUserSurfaceConfig, 0, sizeof(mUserSurfaceConfig)); + } memset(&mEGL, 0, sizeof(mEGL)); memset(&mGL, 0, sizeof(mGL)); - mIsGraphicsContext = isGraphics; + mIsGraphicsContext = sc != NULL; int status; pthread_attr_t threadAttr; @@ -417,6 +613,7 @@ Context::Context(Device *dev, bool isGraphics, bool useDepth) } } gThreadTLSKeyCount++; + pthread_mutex_unlock(&gInitMutex); // Global init done at this point. @@ -429,20 +626,38 @@ Context::Context(Device *dev, bool isGraphics, bool useDepth) mWndSurface = NULL; - objDestroyOOBInit(); timerInit(); timerSet(RS_TIMER_INTERNAL); - LOGV("RS Launching thread"); + 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."); + return; } - while(!mRunning) { usleep(100); } + mWorkers.mCompleteSignal.init(); + mWorkers.mRunningCount = 0; + mWorkers.mLaunchCount = 0; + 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; + } + } pthread_attr_destroy(&threadAttr); } @@ -455,8 +670,6 @@ Context::~Context() mIO.shutdown(); int status = pthread_join(mThreadId, &res); - mObjDestroy.mNeedToEmpty = true; - objDestroyOOBRun(); // Global structure cleanup. pthread_mutex_lock(&gInitMutex); @@ -469,8 +682,6 @@ Context::~Context() mDev = NULL; } pthread_mutex_unlock(&gInitMutex); - - objDestroyOOBDestroy(); } void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) @@ -479,28 +690,21 @@ void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) EGLBoolean ret; if (mEGL.mSurface != NULL) { - ret = eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + 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; - mEGL.mWidth = 0; - mEGL.mHeight = 0; - mWidth = 0; - mHeight = 0; + mWidth = 1; + mHeight = 1; } mWndSurface = sur; if (mWndSurface != NULL) { - bool first = false; - if (!mEGL.mContext) { - first = true; - pthread_mutex_lock(&gInitMutex); - initEGL(true); - pthread_mutex_unlock(&gInitMutex); - } + mWidth = w; + mHeight = h; mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL); checkEglError("eglCreateWindowSurface"); @@ -511,57 +715,7 @@ void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); checkEglError("eglMakeCurrent", ret); - eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); - eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); - mWidth = w; - mHeight = h; - mStateVertex.updateSize(this, w, h); - - if ((int)mWidth != mEGL.mWidth || (int)mHeight != mEGL.mHeight) { - LOGE("EGL/Surface mismatch EGL (%i x %i) SF (%i x %i)", mEGL.mWidth, mEGL.mHeight, mWidth, mHeight); - } - - if (first) { - 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"); - } 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"); - } - + mStateVertex.updateSize(this); } } @@ -583,7 +737,7 @@ void Context::setRootScript(Script *s) mRootScript.set(s); } -void Context::setFragmentStore(ProgramFragmentStore *pfs) +void Context::setFragmentStore(ProgramStore *pfs) { rsAssert(mIsGraphicsContext); if (pfs == NULL) { @@ -623,6 +777,16 @@ void Context::setVertex(ProgramVertex *pv) } } +void Context::setFont(Font *f) +{ + rsAssert(mIsGraphicsContext); + if (f == NULL) { + mFont.set(mStateFont.mDefault); + } else { + mFont.set(f); + } +} + void Context::assignName(ObjectBase *obj, const char *name, uint32_t len) { rsAssert(!obj->getName()); @@ -640,90 +804,13 @@ void Context::removeName(ObjectBase *obj) } } -ObjectBase * Context::lookupName(const char *name) const -{ - for(size_t ct=0; ct < mNames.size(); ct++) { - if (!strcmp(name, mNames[ct]->getName())) { - return mNames[ct]; - } - } - return NULL; -} - -void Context::appendNameDefines(String8 *str) const -{ - char buf[256]; - for (size_t ct=0; ct < mNames.size(); ct++) { - str->append("#define NAMED_"); - str->append(mNames[ct]->getName()); - str->append(" "); - sprintf(buf, "%i\n", (int)mNames[ct]); - str->append(buf); - } -} - -bool Context::objDestroyOOBInit() -{ - int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL); - if (status) { - LOGE("Context::ObjDestroyOOBInit mutex init failure"); - return false; - } - return true; -} - -void Context::objDestroyOOBRun() -{ - if (mObjDestroy.mNeedToEmpty) { - int status = pthread_mutex_lock(&mObjDestroy.mMutex); - if (status) { - LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); - return; - } - - for (size_t ct = 0; ct < mObjDestroy.mDestroyList.size(); ct++) { - mObjDestroy.mDestroyList[ct]->decUserRef(); - } - mObjDestroy.mDestroyList.clear(); - mObjDestroy.mNeedToEmpty = false; - - status = pthread_mutex_unlock(&mObjDestroy.mMutex); - if (status) { - LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); - } - } -} - -void Context::objDestroyOOBDestroy() -{ - rsAssert(!mObjDestroy.mNeedToEmpty); - pthread_mutex_destroy(&mObjDestroy.mMutex); -} - -void Context::objDestroyAdd(ObjectBase *obj) -{ - int status = pthread_mutex_lock(&mObjDestroy.mMutex); - if (status) { - LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status); - return; - } - - mObjDestroy.mNeedToEmpty = true; - mObjDestroy.mDestroyList.add(obj); - - status = pthread_mutex_unlock(&mObjDestroy.mMutex); - if (status) { - LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status); - } -} - uint32_t Context::getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait) { //LOGE("getMessageToClient %i %i", bufferLen, wait); + *receiveLen = 0; if (!wait) { if (mIO.mToClient.isEmpty()) { // No message to get and not going to wait for one. - receiveLen = 0; return 0; } } @@ -751,15 +838,19 @@ bool Context::sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool w return false; } if (!waitForSpace) { - if (mIO.mToClient.getFreeSpace() < len) { + if (!mIO.mToClient.makeSpaceNonBlocking(len + 8)) { // Not enough room, and not waiting. return false; } } //LOGE("sendMessageToClient 2"); - void *p = mIO.mToClient.reserve(len); - memcpy(p, data, len); - mIO.mToClient.commit(cmdID, len); + if (len > 0) { + void *p = mIO.mToClient.reserve(len); + memcpy(p, data, len); + mIO.mToClient.commit(cmdID, len); + } else { + mIO.mToClient.commit(cmdID, 0); + } //LOGE("sendMessageToClient 3"); return true; } @@ -799,15 +890,14 @@ void Context::dumpDebug() const LOGE("RS Context debug"); LOGE(" EGL ver %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); - LOGE(" EGL context %p surface %p, w=%i h=%i Display=%p", mEGL.mContext, - mEGL.mSurface, mEGL.mWidth, mEGL.mHeight, mEGL.mDisplay); + 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, useDepth %i, paused %i", mRunning, mExit, mUseDepth, mPaused); + 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); @@ -822,6 +912,9 @@ void Context::dumpDebug() const namespace android { namespace renderscript { +void rsi_ContextFinish(Context *rsc) +{ +} void rsi_ContextBindRootScript(Context *rsc, RsScript vs) { @@ -841,9 +934,9 @@ void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs) s->bindToContext(&rsc->mStateSampler, slot); } -void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs) +void rsi_ContextBindProgramStore(Context *rsc, RsProgramStore vpfs) { - ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs); + ProgramStore *pfs = static_cast<ProgramStore *>(vpfs); rsc->setFragmentStore(pfs); } @@ -865,15 +958,27 @@ void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv) rsc->setVertex(pv); } +void rsi_ContextBindFont(Context *rsc, RsFont vfont) +{ + Font *font = static_cast<Font *>(vfont); + rsc->setFont(font); +} + void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len) { ObjectBase *ob = static_cast<ObjectBase *>(obj); rsc->assignName(ob, name, len); } -void rsi_ObjDestroy(Context *rsc, void *obj) +void rsi_GetName(Context *rsc, void * obj, const char **name) { ObjectBase *ob = static_cast<ObjectBase *>(obj); + (*name) = ob->getName(); +} + +void rsi_ObjDestroy(Context *rsc, void *optr) +{ + ObjectBase *ob = static_cast<ObjectBase *>(optr); rsc->removeName(ob); ob->decUserRef(); } @@ -920,15 +1025,16 @@ RsContext rsContextCreate(RsDevice vdev, uint32_t version) { LOGV("rsContextCreate %p", vdev); Device * dev = static_cast<Device *>(vdev); - Context *rsc = new Context(dev, false, false); + Context *rsc = new Context(dev, NULL); return rsc; } -RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, bool useDepth) +RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, RsSurfaceConfig sc) { - LOGV("rsContextCreateGL %p, %i", vdev, useDepth); + LOGV("rsContextCreateGL %p", vdev); Device * dev = static_cast<Device *>(vdev); - Context *rsc = new Context(dev, true, useDepth); + Context *rsc = new Context(dev, &sc); + LOGV("rsContextCreateGL ret %p ", rsc); return rsc; } @@ -938,12 +1044,6 @@ void rsContextDestroy(RsContext vrsc) delete rsc; } -void rsObjDestroyOOB(RsContext vrsc, void *obj) -{ - Context * rsc = static_cast<Context *>(vrsc); - rsc->objDestroyAdd(static_cast<ObjectBase *>(obj)); -} - uint32_t rsContextGetMessage(RsContext vrsc, void *data, size_t *receiveLen, size_t bufferLen, bool wait) { Context * rsc = static_cast<Context *>(vrsc); diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 709730e..dbe2c79 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -18,21 +18,21 @@ #define ANDROID_RS_CONTEXT_H #include "rsUtils.h" +#include "rsMutex.h" #include "rsThreadIO.h" #include "rsType.h" #include "rsMatrix.h" #include "rsAllocation.h" -#include "rsSimpleMesh.h" #include "rsMesh.h" #include "rsDevice.h" #include "rsScriptC.h" #include "rsAllocation.h" #include "rsAdapter.h" #include "rsSampler.h" -#include "rsLight.h" +#include "rsFont.h" #include "rsProgramFragment.h" -#include "rsProgramFragmentStore.h" +#include "rsProgramStore.h" #include "rsProgramRaster.h" #include "rsProgramVertex.h" #include "rsShaderCache.h" @@ -48,10 +48,28 @@ namespace android { namespace renderscript { +#if 0 +#define CHECK_OBJ(o) { \ + GET_TLS(); \ + if(!ObjectBase::isValid(rsc, (const ObjectBase *)o)) { \ + LOGE("Bad object %p at %s, %i", o, __FILE__, __LINE__); \ + } \ +} +#define CHECK_OBJ_OR_NULL(o) { \ + GET_TLS(); \ + if(o && !ObjectBase::isValid(rsc, (const ObjectBase *)o)) { \ + LOGE("Bad object %p at %s, %i", o, __FILE__, __LINE__); \ + } \ +} +#else +#define CHECK_OBJ(o) +#define CHECK_OBJ_OR_NULL(o) +#endif + class Context { public: - Context(Device *, bool isGraphics, bool useDepth); + Context(Device *, const RsSurfaceConfig *sc); ~Context(); static pthread_key_t gThreadTLSKey; @@ -63,18 +81,21 @@ public: Context * mContext; Script * mScript; }; + ScriptTLSStruct *mTlsStruct; + RsSurfaceConfig mUserSurfaceConfig; + typedef void (*WorkerCallback_t)(void *usr, uint32_t idx); //StructuredAllocationContext mStateAllocation; ElementState mStateElement; TypeState mStateType; SamplerState mStateSampler; ProgramFragmentState mStateFragment; - ProgramFragmentStoreState mStateFragmentStore; + ProgramStoreState mStateFragmentStore; ProgramRasterState mStateRaster; ProgramVertexState mStateVertex; - LightState mStateLight; VertexArrayState mStateVertexArray; + FontState mStateFont; ScriptCState mScriptC; ShaderCache mShaderCache; @@ -84,16 +105,19 @@ public: void setRaster(ProgramRaster *); void setVertex(ProgramVertex *); void setFragment(ProgramFragment *); - void setFragmentStore(ProgramFragmentStore *); + void setFragmentStore(ProgramStore *); + void setFont(Font *); void updateSurface(void *sur); const ProgramFragment * getFragment() {return mFragment.get();} - const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();} + const ProgramStore * getFragmentStore() {return mFragmentStore.get();} const ProgramRaster * getRaster() {return mRaster.get();} const ProgramVertex * getVertex() {return mVertex.get();} + Font * getFont() {return mFont.get();} bool setupCheck(); + void setupProgramStore(); bool checkDriver() const {return mEGL.mSurface != 0;} void pause(); @@ -103,12 +127,10 @@ public: void assignName(ObjectBase *obj, const char *name, uint32_t len); void removeName(ObjectBase *obj); - ObjectBase * lookupName(const char *name) const; - void appendNameDefines(String8 *str) const; uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait); bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace); - uint32_t runScript(Script *s, uint32_t launchID); + uint32_t runScript(Script *s); void initToClient(); void deinitToClient(); @@ -119,19 +141,21 @@ public: ProgramVertex * getDefaultProgramVertex() const { return mStateVertex.mDefault.get(); } - ProgramFragmentStore * getDefaultProgramFragmentStore() const { + ProgramStore * getDefaultProgramStore() const { return mStateFragmentStore.mDefault.get(); } ProgramRaster * getDefaultProgramRaster() const { return mStateRaster.mDefault.get(); } + Font* getDefaultFont() const { + return mStateFont.mDefault.get(); + } - uint32_t getWidth() const {return mEGL.mWidth;} - uint32_t getHeight() const {return mEGL.mHeight;} + uint32_t getWidth() const {return mWidth;} + uint32_t getHeight() const {return mHeight;} ThreadIO mIO; - void objDestroyAdd(ObjectBase *); // Timers enum Timers { @@ -148,24 +172,31 @@ public: void timerPrint(); void timerFrame(); - bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); } - bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; } - struct { bool mLogTimes; bool mLogScripts; bool mLogObjects; bool mLogShaders; + bool mLogShadersAttr; + bool mLogShadersUniforms; + bool mLogVisual; } props; void dumpDebug() const; void checkError(const char *) const; const char * getError(RsError *); - void setError(RsError e, const char *msg); + void setError(RsError e, const char *msg = NULL); mutable const ObjectBase * mObjHead; bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;} + 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;} + + void launchThreads(WorkerCallback_t cbk, void *data); + uint32_t getWorkerPoolSize() const {return (uint32_t)mWorkers.mCount;} protected: Device *mDev; @@ -177,8 +208,7 @@ protected: EGLConfig mConfig; EGLContext mContext; EGLSurface mSurface; - EGLint mWidth; - EGLint mHeight; + EGLSurface mSurfaceDefault; EGLDisplay mDisplay; } mEGL; @@ -202,6 +232,7 @@ protected: int32_t mMaxVertexTextureUnits; bool OES_texture_npot; + float EXT_texture_max_aniso; } mGL; uint32_t mWidth; @@ -211,7 +242,6 @@ protected: bool mRunning; bool mExit; - bool mUseDepth; bool mPaused; RsError mError; const char *mErrorMsg; @@ -219,32 +249,40 @@ 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; - ObjectBaseRef<ProgramFragmentStore> mFragmentStore; + ObjectBaseRef<ProgramStore> mFragmentStore; ObjectBaseRef<ProgramRaster> mRaster; + ObjectBaseRef<Font> mFont; - - struct ObjDestroyOOB { - pthread_mutex_t mMutex; - Vector<ObjectBase *> mDestroyList; - bool mNeedToEmpty; - }; - ObjDestroyOOB mObjDestroy; - bool objDestroyOOBInit(); - void objDestroyOOBRun(); - void objDestroyOOBDestroy(); + void displayDebugStats(); private: Context(); - void initEGL(bool useGL2); + void initEGL(); + void initGLThread(); void deinitEGL(); uint32_t runRootScript(); static void * threadProc(void *); + static void * helperThreadProc(void *); ANativeWindow *mWndSurface; @@ -258,6 +296,9 @@ private: uint32_t mTimeMSLastFrame; uint32_t mTimeMSLastScript; uint32_t mTimeMSLastSwap; + uint32_t mAverageFPSFrameCount; + uint64_t mAverageFPSStartTime; + uint32_t mAverageFPS; }; } diff --git a/libs/rs/rsContextHostStub.h b/libs/rs/rsContextHostStub.h new file mode 100644 index 0000000..aa0205d --- /dev/null +++ b/libs/rs/rsContextHostStub.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_CONTEXT_HOST_STUB_H +#define ANDROID_RS_CONTEXT_HOST_STUB_H + +#include "rsUtils.h" +//#include "rsMutex.h" + +//#include "rsThreadIO.h" +#include "rsType.h" +#include "rsMatrix.h" +#include "rsAllocation.h" +#include "rsMesh.h" +//#include "rsDevice.h" +#include "rsScriptC.h" +#include "rsAllocation.h" +#include "rsAdapter.h" +#include "rsSampler.h" +#include "rsProgramFragment.h" +#include "rsProgramStore.h" +#include "rsProgramRaster.h" +#include "rsProgramVertex.h" +#include "rsShaderCache.h" +#include "rsVertexArray.h" + +//#include "rsgApiStructs.h" +//#include "rsLocklessFifo.h" + +//#include <ui/egl/android_natives.h> + +// --------------------------------------------------------------------------- +namespace android { + +namespace renderscript { + +class Device; + +class Context +{ +public: + Context(Device *, bool isGraphics, bool useDepth) { + mObjHead = NULL; + } + ~Context() { + } + + + //StructuredAllocationContext mStateAllocation; + ElementState mStateElement; + TypeState mStateType; + SamplerState mStateSampler; + //ProgramFragmentState mStateFragment; + ProgramStoreState mStateFragmentStore; + //ProgramRasterState mStateRaster; + //ProgramVertexState mStateVertex; + VertexArrayState mStateVertexArray; + + //ScriptCState mScriptC; + ShaderCache mShaderCache; + + + //bool setupCheck(); + bool checkDriver() const {return false;} + + ProgramFragment * getDefaultProgramFragment() const { + return NULL; + } + ProgramVertex * getDefaultProgramVertex() const { + return NULL; + } + ProgramStore * getDefaultProgramStore() const { + return NULL; + } + ProgramRaster * getDefaultProgramRaster() const { + return NULL; + } + + uint32_t getWidth() const {return 0;} + uint32_t getHeight() const {return 0;} + + // Timers + enum Timers { + RS_TIMER_IDLE, + RS_TIMER_INTERNAL, + RS_TIMER_SCRIPT, + RS_TIMER_CLEAR_SWAP, + _RS_TIMER_TOTAL + }; + + bool checkVersion1_1() const {return false; } + bool checkVersion2_0() const {return false; } + + struct { + bool mLogTimes; + bool mLogScripts; + bool mLogObjects; + bool mLogShaders; + bool mLogShadersAttr; + bool mLogShadersUniforms; + bool mLogVisual; + } props; + + void dumpDebug() const { } + void checkError(const char *) const { }; + void setError(RsError e, const char *msg = NULL) { } + + mutable const ObjectBase * mObjHead; + + bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;} + float ext_texture_max_aniso() const {return 1.0f;} + uint32_t getMaxFragmentTextures() const {return mGL.mMaxFragmentTextureImageUnits;} + uint32_t getMaxFragmentUniformVectors() const {return mGL.mMaxFragmentUniformVectors;} + uint32_t getMaxVertexUniformVectors() const {return mGL.mMaxVertexUniformVectors;} + +protected: + + 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; + } mGL; + +}; + +} +} +#endif diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp index b670ad4..a96b114 100644 --- a/libs/rs/rsDevice.cpp +++ b/libs/rs/rsDevice.cpp @@ -15,7 +15,11 @@ */ #include "rsDevice.h" +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif using namespace android; using namespace android::renderscript; @@ -33,7 +37,7 @@ Device::~Device() void Device::addContext(Context *rsc) { - mContexts.add(rsc); + mContexts.push(rsc); } void Device::removeContext(Context *rsc) diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp index 6288bc4..9e6fbd5 100644 --- a/libs/rs/rsElement.cpp +++ b/libs/rs/rsElement.cpp @@ -14,9 +14,14 @@ * limitations under the License. */ -#include "rsContext.h" +#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" #include <GLES/gl.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#endif using namespace android; using namespace android::renderscript; @@ -29,6 +34,7 @@ Element::Element(Context *rsc) : ObjectBase(rsc) mAllocLine = __LINE__; mFields = NULL; mFieldCount = 0; + mHasReference = false; } @@ -48,6 +54,7 @@ void Element::clear() delete [] mFields; mFields = NULL; mFieldCount = 0; + mHasReference = false; } size_t Element::getSizeBits() const @@ -58,31 +65,117 @@ size_t Element::getSizeBits() const size_t total = 0; for (size_t ct=0; ct < mFieldCount; ct++) { - total += mFields[ct].e->mBits; + total += mFields[ct].e->mBits * mFields[ct].arraySize; } return total; } -size_t Element::getFieldOffsetBits(uint32_t componentNumber) const +void Element::dumpLOGV(const char *prefix) const { - size_t offset = 0; - for (uint32_t ct = 0; ct < componentNumber; ct++) { - offset += mFields[ct].e->mBits; + ObjectBase::dumpLOGV(prefix); + LOGV("%s Element: fieldCount: %i, size bytes: %i", prefix, mFieldCount, getSizeBytes()); + for (uint32_t ct = 0; ct < mFieldCount; ct++) { + LOGV("%s Element field index: %u ------------------", prefix, ct); + LOGV("%s name: %s, offsetBits: %u, arraySize: %u", + prefix, mFields[ct].name.string(), mFields[ct].offsetBits, mFields[ct].arraySize); + mFields[ct].e->dumpLOGV(prefix); } - return offset; } -void Element::dumpLOGV(const char *prefix) const +void Element::serialize(OStream *stream) const { - ObjectBase::dumpLOGV(prefix); - LOGV("%s Element: components %i, size %i", prefix, mFieldCount, mBits); - for (uint32_t ct = 0; ct < mFieldCount; ct++) { - char buf[1024]; - sprintf(buf, "%s component %i: ", prefix, ct); - //mComponents[ct]->dumpLOGV(buf); + // Need to identify ourselves + stream->addU32((uint32_t)getClassId()); + + String8 name(getName()); + stream->addString(&name); + + mComponent.serialize(stream); + + // Now serialize all the fields + stream->addU32(mFieldCount); + for(uint32_t ct = 0; ct < mFieldCount; ct++) { + stream->addString(&mFields[ct].name); + stream->addU32(mFields[ct].arraySize); + mFields[ct].e->serialize(stream); + } +} + +Element *Element::createFromStream(Context *rsc, IStream *stream) +{ + // First make sure we are reading the correct object + RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); + if(classID != RS_A3D_CLASS_ID_ELEMENT) { + LOGE("element loading skipped due to invalid class id\n"); + return NULL; + } + + String8 name; + stream->loadString(&name); + + Element *elem = new Element(rsc); + elem->mComponent.loadFromStream(stream); + elem->mBits = elem->mComponent.getBits(); + elem->mHasReference = elem->mComponent.isReference(); + + elem->mFieldCount = stream->loadU32(); + if(elem->mFieldCount) { + uint32_t offset = 0; + elem->mFields = new ElementField_t [elem->mFieldCount]; + for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) { + stream->loadString(&elem->mFields[ct].name); + elem->mFields[ct].arraySize = stream->loadU32(); + Element *fieldElem = Element::createFromStream(rsc, stream); + elem->mFields[ct].e.set(fieldElem); + elem->mFields[ct].offsetBits = offset; + offset += fieldElem->getSizeBits(); + // Check if our sub-elements have references + if(fieldElem->mHasReference) { + elem->mHasReference = true; + } + } + } + + // We need to check if this already exists + for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) { + Element *ee = rsc->mStateElement.mElements[ct]; + if(ee->isEqual(elem)) { + delete elem; + ee->incUserRef(); + return ee; + } } + + rsc->mStateElement.mElements.push(elem); + return elem; } +bool Element::isEqual(const Element *other) const { + if(other == NULL) { + return false; + } + if (!other->getFieldCount() && !mFieldCount) { + if((other->getType() == getType()) && + (other->getKind() == getKind()) && + (other->getComponent().getIsNormalized() == getComponent().getIsNormalized()) && + (other->getComponent().getVectorSize() == getComponent().getVectorSize())) { + return true; + } + return false; + } + if (other->getFieldCount() == mFieldCount) { + for (uint32_t i=0; i < mFieldCount; i++) { + if ((!other->mFields[i].e->isEqual(mFields[i].e.get())) || + (other->mFields[i].name.length() != mFields[i].name.length()) || + (other->mFields[i].name != mFields[i].name) || + (other->mFields[i].arraySize != mFields[i].arraySize)) { + return false; + } + } + return true; + } + return false; +} const Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk, bool isNorm, uint32_t vecSize) @@ -104,12 +197,13 @@ const Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk, Element *e = new Element(rsc); e->mComponent.set(dt, dk, isNorm, vecSize); e->mBits = e->mComponent.getBits(); + e->mHasReference = e->mComponent.isReference(); rsc->mStateElement.mElements.push(e); return e; } const Element * Element::create(Context *rsc, size_t count, const Element **ein, - const char **nin, const size_t * lengths) + const char **nin, const size_t * lengths, const uint32_t *asin) { // Look for an existing match. for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) { @@ -119,7 +213,8 @@ const Element * Element::create(Context *rsc, size_t count, const Element **ein, for (uint32_t i=0; i < count; i++) { if ((ee->mFields[i].e.get() != ein[i]) || (ee->mFields[i].name.length() != lengths[i]) || - (ee->mFields[i].name != nin[i])) { + (ee->mFields[i].name != nin[i]) || + (ee->mFields[i].arraySize != asin[i])) { match = false; break; } @@ -134,37 +229,24 @@ const Element * Element::create(Context *rsc, size_t count, const Element **ein, Element *e = new Element(rsc); e->mFields = new ElementField_t [count]; e->mFieldCount = count; + size_t bits = 0; for (size_t ct=0; ct < count; ct++) { e->mFields[ct].e.set(ein[ct]); e->mFields[ct].name.setTo(nin[ct], lengths[ct]); + e->mFields[ct].offsetBits = bits; + e->mFields[ct].arraySize = asin[ct]; + bits += ein[ct]->getSizeBits(); + + if (ein[ct]->mHasReference) { + e->mHasReference = true; + } } rsc->mStateElement.mElements.push(e); return e; } -String8 Element::getCStructBody(uint32_t indent) const -{ - String8 si; - for (uint32_t ct=0; ct < indent; ct++) { - si.append(" "); - } - - String8 s(si); - s.append("{\n"); - for (uint32_t ct = 0; ct < mFieldCount; ct++) { - s.append(si); - s.append(mFields[ct].e->getCType(indent+4)); - s.append(" "); - s.append(mFields[ct].name); - s.append(";\n"); - } - s.append(si); - s.append("}"); - return s; -} - -String8 Element::getCType(uint32_t indent) const +String8 Element::getGLSLType(uint32_t indent) const { String8 s; for (uint32_t ct=0; ct < indent; ct++) { @@ -173,38 +255,70 @@ String8 Element::getCType(uint32_t indent) const if (!mFieldCount) { // Basic component. - s.append(mComponent.getCType()); + s.append(mComponent.getGLSLType()); } else { - s.append("struct "); - s.append(getCStructBody(indent)); + rsAssert(0); + //s.append("struct "); + //s.append(getCStructBody(indent)); } return s; } -String8 Element::getGLSLType(uint32_t indent) const +void Element::incRefs(const void *ptr) const { - String8 s; - for (uint32_t ct=0; ct < indent; ct++) { - s.append(" "); + if (!mFieldCount) { + if (mComponent.isReference()) { + ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr); + ObjectBase *ob = obp[0]; + if (ob) ob->incSysRef(); + } + return; } + const uint8_t *p = static_cast<const uint8_t *>(ptr); + for (uint32_t i=0; i < mFieldCount; i++) { + if (mFields[i].e->mHasReference) { + p = &p[mFields[i].offsetBits >> 3]; + for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) { + mFields[i].e->incRefs(p); + p += mFields[i].e->getSizeBytes(); + } + } + } +} + +void Element::decRefs(const void *ptr) const +{ if (!mFieldCount) { - // Basic component. - s.append(mComponent.getGLSLType()); - } else { - rsAssert(0); - //s.append("struct "); - //s.append(getCStructBody(indent)); + if (mComponent.isReference()) { + ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr); + ObjectBase *ob = obp[0]; + if (ob) ob->decSysRef(); + } + return; } - return s; + const uint8_t *p = static_cast<const uint8_t *>(ptr); + for (uint32_t i=0; i < mFieldCount; i++) { + if (mFields[i].e->mHasReference) { + p = &p[mFields[i].offsetBits >> 3]; + for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) { + mFields[i].e->decRefs(p); + p += mFields[i].e->getSizeBytes(); + } + } + } } - ElementState::ElementState() { + const uint32_t initialCapacity = 32; + mBuilderElements.setCapacity(initialCapacity); + mBuilderNameStrings.setCapacity(initialCapacity); + mBuilderNameLengths.setCapacity(initialCapacity); + mBuilderArrays.setCapacity(initialCapacity); } ElementState::~ElementState() @@ -212,6 +326,29 @@ ElementState::~ElementState() rsAssert(!mElements.size()); } +void ElementState::elementBuilderBegin() { + mBuilderElements.clear(); + mBuilderNameStrings.clear(); + mBuilderNameLengths.clear(); + mBuilderArrays.clear(); +} + +void ElementState::elementBuilderAdd(const Element *e, const char *nameStr, uint32_t arraySize) { + mBuilderElements.push(e); + mBuilderNameStrings.push(nameStr); + mBuilderNameLengths.push(strlen(nameStr)); + mBuilderArrays.push(arraySize); + +} + +const Element *ElementState::elementBuilderCreate(Context *rsc) { + return Element::create(rsc, mBuilderElements.size(), + &(mBuilderElements.editArray()[0]), + &(mBuilderNameStrings.editArray()[0]), + mBuilderNameLengths.editArray(), + mBuilderArrays.editArray()); +} + ///////////////////////////////////////// // @@ -235,14 +372,41 @@ RsElement rsi_ElementCreate2(Context *rsc, size_t count, const RsElement * ein, const char ** names, - const size_t * nameLengths) + const size_t * nameLengths, + const uint32_t * arraySizes) { //LOGE("rsi_ElementCreate2 %i", count); - const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths); + const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes); e->incUserRef(); return (RsElement)e; } +void rsi_ElementGetNativeData(Context *rsc, RsElement elem, uint32_t *elemData, uint32_t elemDataSize) +{ + rsAssert(elemDataSize == 5); + // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements + Element *e = static_cast<Element *>(elem); + + (*elemData++) = (uint32_t)e->getType(); + (*elemData++) = (uint32_t)e->getKind(); + (*elemData++) = e->getComponent().getIsNormalized() ? 1 : 0; + (*elemData++) = e->getComponent().getVectorSize(); + (*elemData++) = e->getFieldCount(); + +} + +void rsi_ElementGetSubElements(Context *rsc, RsElement elem, uint32_t *ids, const char **names, uint32_t dataSize) +{ + Element *e = static_cast<Element *>(elem); + rsAssert(e->getFieldCount() == dataSize); + + for(uint32_t i = 0; i < dataSize; i ++) { + ids[i] = (uint32_t)e->getField(i); + names[i] = e->getFieldName(i); + } + +} + } } diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h index 02a1ca2..70e2619 100644 --- a/libs/rs/rsElement.h +++ b/libs/rs/rsElement.h @@ -40,30 +40,40 @@ public: return (getSizeBits() + 7) >> 3; } - size_t getFieldOffsetBits(uint32_t componentNumber) const; + size_t getFieldOffsetBits(uint32_t componentNumber) const { + return mFields[componentNumber].offsetBits; + } size_t getFieldOffsetBytes(uint32_t componentNumber) const { - return (getFieldOffsetBits(componentNumber) + 7) >> 3; + return mFields[componentNumber].offsetBits >> 3; } uint32_t getFieldCount() const {return mFieldCount;} const Element * getField(uint32_t idx) const {return mFields[idx].e.get();} const char * getFieldName(uint32_t idx) const {return mFields[idx].name.string();} + uint32_t getFieldArraySize(uint32_t idx) const {return mFields[idx].arraySize;} const Component & getComponent() const {return mComponent;} RsDataType getType() const {return mComponent.getType();} RsDataKind getKind() const {return mComponent.getKind();} uint32_t getBits() const {return mBits;} - String8 getCType(uint32_t indent=0) const; - String8 getCStructBody(uint32_t indent=0) const; String8 getGLSLType(uint32_t indent=0) const; void dumpLOGV(const char *prefix) const; + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_ELEMENT; } + static Element *createFromStream(Context *rsc, IStream *stream); static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk, bool isNorm, uint32_t vecSize); static const Element * create(Context *rsc, size_t count, const Element **, - const char **, const size_t * lengths); + const char **, const size_t * lengths, const uint32_t *asin); + + void incRefs(const void *) const; + void decRefs(const void *) const; + bool getHasReferences() const {return mHasReference;} + + bool isEqual(const Element *other) const; protected: // deallocate any components that are part of this element. @@ -72,9 +82,12 @@ protected: typedef struct { String8 name; ObjectBaseRef<const Element> e; + uint32_t offsetBits; + uint32_t arraySize; } ElementField_t; ElementField_t *mFields; size_t mFieldCount; + bool mHasReference; Element(Context *); @@ -89,8 +102,17 @@ public: ElementState(); ~ElementState(); + void elementBuilderBegin(); + void elementBuilderAdd(const Element *e, const char *nameStr, uint32_t arraySize); + const Element *elementBuilderCreate(Context *rsc); + // Cache of all existing elements. - Vector<const Element *> mElements; + Vector<Element *> mElements; +private: + Vector<const Element *> mBuilderElements; + Vector<const char*> mBuilderNameStrings; + Vector<size_t> mBuilderNameLengths; + Vector<uint32_t> mBuilderArrays; }; diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp index e3272c5..c90edc2 100644 --- a/libs/rs/rsFileA3D.cpp +++ b/libs/rs/rsFileA3D.cpp @@ -15,81 +15,193 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif - -#include <utils/String8.h> #include "rsFileA3D.h" #include "rsMesh.h" +#include "rsAnimation.h" + using namespace android; using namespace android::renderscript; +FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) +{ + mAlloc = NULL; + mData = NULL; + mWriteStream = NULL; + mReadStream = NULL; + + mMajorVersion = 0; + mMinorVersion = 1; + mDataSize = 0; +} +FileA3D::~FileA3D() +{ + for(size_t i = 0; i < mIndex.size(); i ++) { + delete mIndex[i]; + } + for(size_t i = 0; i < mWriteIndex.size(); i ++) { + delete mWriteIndex[i]; + } + if(mWriteStream) { + delete mWriteStream; + } + if(mReadStream) { + delete mWriteStream; + } + if(mAlloc) { + free(mAlloc); + } +} -FileA3D::FileA3D() +void FileA3D::parseHeader(IStream *headerStream) { - mRsc = NULL; + mMajorVersion = headerStream->loadU32(); + mMinorVersion = headerStream->loadU32(); + uint32_t flags = headerStream->loadU32(); + mUse64BitOffsets = (flags & 1) != 0; + + uint32_t numIndexEntries = headerStream->loadU32(); + for(uint32_t i = 0; i < numIndexEntries; i ++) { + A3DIndexEntry *entry = new A3DIndexEntry(); + headerStream->loadString(&entry->mObjectName); + LOGV("Header data, entry name = %s", entry->mObjectName.string()); + entry->mType = (RsA3DClassID)headerStream->loadU32(); + if(mUse64BitOffsets){ + entry->mOffset = headerStream->loadOffset(); + entry->mLength = headerStream->loadOffset(); + } + else { + entry->mOffset = headerStream->loadU32(); + entry->mLength = headerStream->loadU32(); + } + entry->mRsObj = NULL; + mIndex.push(entry); + } } -FileA3D::~FileA3D() +bool FileA3D::load(const void *data, size_t length) { + const uint8_t *localData = (const uint8_t *)data; + + size_t lengthRemaining = length; + size_t magicStrLen = 12; + if ((length < magicStrLen) || + memcmp(data, "Android3D_ff", magicStrLen)) { + return false; + } + + localData += magicStrLen; + lengthRemaining -= magicStrLen; + + // Next we get our header size + uint64_t headerSize = 0; + if(lengthRemaining < sizeof(headerSize)) { + return false; + } + + memcpy(&headerSize, localData, sizeof(headerSize)); + localData += sizeof(headerSize); + lengthRemaining -= sizeof(headerSize); + + if(lengthRemaining < headerSize) { + return false; + } + + uint8_t *headerData = (uint8_t *)malloc(headerSize); + if(!headerData) { + return false; + } + + memcpy(headerData, localData, headerSize); + + // Now open the stream to parse the header + IStream headerStream(headerData, false); + parseHeader(&headerStream); + + free(headerData); + + localData += headerSize; + lengthRemaining -= headerSize; + + if(lengthRemaining < sizeof(mDataSize)) { + return false; + } + + // Read the size of the data + memcpy(&mDataSize, localData, sizeof(mDataSize)); + localData += sizeof(mDataSize); + lengthRemaining -= sizeof(mDataSize); + + if(lengthRemaining < mDataSize) { + return false; + } + + // We should know enough to read the file in at this point. + mAlloc = malloc(mDataSize); + if (!mAlloc) { + return false; + } + mData = (uint8_t *)mAlloc; + memcpy(mAlloc, localData, mDataSize); + + mReadStream = new IStream(mData, mUse64BitOffsets); + + return true; } -bool FileA3D::load(Context *rsc, FILE *f) +bool FileA3D::load(FILE *f) { char magicString[12]; size_t len; - LOGE("file open 1"); + LOGV("file open 1"); len = fread(magicString, 1, 12, f); if ((len != 12) || memcmp(magicString, "Android3D_ff", 12)) { return false; } - LOGE("file open 2"); - len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f); - if (len != sizeof(mMajorVersion)) { + // Next thing is the size of the header + uint64_t headerSize = 0; + len = fread(&headerSize, 1, sizeof(headerSize), f); + if (len != sizeof(headerSize) || headerSize == 0) { return false; } - LOGE("file open 3"); - len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f); - if (len != sizeof(mMinorVersion)) { + uint8_t *headerData = (uint8_t *)malloc(headerSize); + if(!headerData) { return false; } - LOGE("file open 4"); - uint32_t flags; - len = fread(&flags, 1, sizeof(flags), f); - if (len != sizeof(flags)) { + len = fread(headerData, 1, headerSize, f); + if (len != headerSize) { return false; } - mUse64BitOffsets = (flags & 1) != 0; - LOGE("file open 64bit = %i", mUse64BitOffsets); + // Now open the stream to parse the header + IStream headerStream(headerData, false); + parseHeader(&headerStream); - if (mUse64BitOffsets) { - len = fread(&mDataSize, 1, sizeof(mDataSize), f); - if (len != sizeof(mDataSize)) { - return false; - } - } else { - uint32_t tmp; - len = fread(&tmp, 1, sizeof(tmp), f); - if (len != sizeof(tmp)) { - return false; - } - mDataSize = tmp; + free(headerData); + + // Next thing is the size of the header + len = fread(&mDataSize, 1, sizeof(mDataSize), f); + if (len != sizeof(mDataSize) || mDataSize == 0) { + return false; } - LOGE("file open size = %lli", mDataSize); + LOGV("file open size = %lli", mDataSize); // We should know enough to read the file in at this point. - fseek(f, SEEK_SET, 0); - mAlloc= malloc(mDataSize); + mAlloc = malloc(mDataSize); if (!mAlloc) { return false; } @@ -99,282 +211,252 @@ bool FileA3D::load(Context *rsc, FILE *f) return false; } - LOGE("file start processing"); - return process(rsc); + mReadStream = new IStream(mData, mUse64BitOffsets); + + LOGV("Header is read an stream initialized"); + return true; } -bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie) -{ - bool ret = false; - IO io(mData + ie->mOffset, mUse64BitOffsets); - - LOGE("process index, type %i", ie->mType); - - switch(ie->mType) { - case CHUNK_ELEMENT: - processChunk_Element(rsc, &io, ie); - break; - case CHUNK_ELEMENT_SOURCE: - processChunk_ElementSource(rsc, &io, ie); - break; - case CHUNK_VERTICIES: - processChunk_Verticies(rsc, &io, ie); - break; - case CHUNK_MESH: - processChunk_Mesh(rsc, &io, ie); - break; - case CHUNK_PRIMITIVE: - processChunk_Primitive(rsc, &io, ie); - break; - default: - LOGE("FileA3D Unknown chunk type"); - break; - } - return (ie->mRsObj != NULL); +size_t FileA3D::getNumIndexEntries() const { + return mIndex.size(); } -bool FileA3D::process(Context *rsc) -{ - LOGE("process"); - IO io(mData + 12, mUse64BitOffsets); - bool ret = true; - - // Build the index first - LOGE("process 1"); - io.loadU32(); // major version, already loaded - io.loadU32(); // minor version, already loaded - LOGE("process 2"); - - io.loadU32(); // flags - io.loadOffset(); // filesize, already loaded. - LOGE("process 4"); - uint64_t mIndexOffset = io.loadOffset(); - uint64_t mStringOffset = io.loadOffset(); - - LOGE("process mIndexOffset= 0x%016llx", mIndexOffset); - LOGE("process mStringOffset= 0x%016llx", mStringOffset); - - IO index(mData + mIndexOffset, mUse64BitOffsets); - IO stringTable(mData + mStringOffset, mUse64BitOffsets); - - uint32_t stringEntryCount = stringTable.loadU32(); - LOGE("stringEntryCount %i", stringEntryCount); - mStrings.setCapacity(stringEntryCount); - mStringIndexValues.setCapacity(stringEntryCount); - if (stringEntryCount) { - uint32_t stringType = stringTable.loadU32(); - LOGE("stringType %i", stringType); - rsAssert(stringType==0); - for (uint32_t ct = 0; ct < stringEntryCount; ct++) { - uint64_t offset = stringTable.loadOffset(); - LOGE("string offset 0x%016llx", offset); - IO tmp(mData + offset, mUse64BitOffsets); - String8 s; - tmp.loadString(&s); - LOGE("string %s", s.string()); - mStrings.push(s); - } +const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const { + if(index < mIndex.size()) { + return mIndex[index]; } + return NULL; +} - LOGE("strings done"); - uint32_t indexEntryCount = index.loadU32(); - LOGE("index count %i", indexEntryCount); - mIndex.setCapacity(indexEntryCount); - for (uint32_t ct = 0; ct < indexEntryCount; ct++) { - A3DIndexEntry e; - uint32_t stringIndex = index.loadU32(); - LOGE("index %i", ct); - LOGE(" string index %i", stringIndex); - e.mType = (A3DChunkType)index.loadU32(); - LOGE(" type %i", e.mType); - e.mOffset = index.loadOffset(); - LOGE(" offset 0x%016llx", e.mOffset); - - if (stringIndex && (stringIndex < mStrings.size())) { - e.mID = mStrings[stringIndex]; - mStringIndexValues.editItemAt(stringIndex) = ct; - LOGE(" id %s", e.mID.string()); - } +ObjectBase *FileA3D::initializeFromEntry(size_t index) { + if(index >= mIndex.size()) { + return NULL; + } - mIndex.push(e); + FileA3D::A3DIndexEntry *entry = mIndex[index]; + if(!entry) { + return NULL; } - LOGE("index done"); - // At this point the index should be fully populated. - // We can now walk though it and load all the objects. - for (uint32_t ct = 0; ct < indexEntryCount; ct++) { - LOGE("processing index entry %i", ct); - processIndex(rsc, &mIndex.editItemAt(ct)); + if(entry->mRsObj) { + entry->mRsObj->incUserRef(); + return entry->mRsObj; } - return ret; + // Seek to the beginning of object + mReadStream->reset(entry->mOffset); + switch (entry->mType) { + case RS_A3D_CLASS_ID_UNKNOWN: + return NULL; + case RS_A3D_CLASS_ID_MESH: + entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_TYPE: + entry->mRsObj = Type::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_ELEMENT: + entry->mRsObj = Element::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_ALLOCATION: + entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_PROGRAM_VERTEX: + entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_PROGRAM_RASTER: + entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT: + entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_PROGRAM_STORE: + entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_SAMPLER: + entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_ANIMATION: + entry->mRsObj = Animation::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_ADAPTER_1D: + entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_ADAPTER_2D: + entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream); + break; + case RS_A3D_CLASS_ID_SCRIPT_C: + return NULL; + } + if(entry->mRsObj) { + entry->mRsObj->incUserRef(); + } + return entry->mRsObj; } - -FileA3D::IO::IO(const uint8_t *buf, bool use64) +bool FileA3D::writeFile(const char *filename) { - mData = buf; - mPos = 0; - mUse64 = use64; -} + if(!mWriteStream) { + LOGE("No objects to write\n"); + return false; + } + if(mWriteStream->getPos() == 0) { + LOGE("No objects to write\n"); + return false; + } -uint64_t FileA3D::IO::loadOffset() -{ - uint64_t tmp; - if (mUse64) { - mPos = (mPos + 7) & (~7); - tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0]; - mPos += sizeof(uint64_t); - return tmp; - } - return loadU32(); -} + FILE *writeHandle = fopen(filename, "wb"); + if(!writeHandle) { + LOGE("Couldn't open the file for writing\n"); + return false; + } -void FileA3D::IO::loadString(String8 *s) -{ - LOGE("loadString"); - uint32_t len = loadU32(); - LOGE("loadString len %i", len); - s->setTo((const char *)&mData[mPos], len); - mPos += len; -} + // Open a new stream to make writing the header easier + OStream headerStream(5*1024, false); + headerStream.addU32(mMajorVersion); + headerStream.addU32(mMinorVersion); + uint32_t is64Bit = 0; + headerStream.addU32(is64Bit); + + uint32_t writeIndexSize = mWriteIndex.size(); + headerStream.addU32(writeIndexSize); + for(uint32_t i = 0; i < writeIndexSize; i ++) { + headerStream.addString(&mWriteIndex[i]->mObjectName); + headerStream.addU32((uint32_t)mWriteIndex[i]->mType); + if(mUse64BitOffsets){ + headerStream.addOffset(mWriteIndex[i]->mOffset); + headerStream.addOffset(mWriteIndex[i]->mLength); + } + else { + uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset; + headerStream.addU32(offset); + offset = (uint32_t)mWriteIndex[i]->mLength; + headerStream.addU32(offset); + } + } + // Write our magic string so we know we are reading the right file + String8 magicString(A3D_MAGIC_KEY); + fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle); -void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie) -{ - Mesh * m = new Mesh(rsc); + // Store the size of the header to make it easier to parse when we read it + uint64_t headerSize = headerStream.getPos(); + fwrite(&headerSize, sizeof(headerSize), 1, writeHandle); + + // Now write our header + fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle); + + // Now write the size of the data part of the file for easier parsing later + uint64_t fileDataSize = mWriteStream->getPos(); + fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle); - m->mPrimitivesCount = io->loadU32(); - m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount]; + fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle); - for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) { - uint32_t index = io->loadU32(); + int status = fclose(writeHandle); - m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj; + if(status != 0) { + LOGE("Couldn't close file\n"); + return false; + } + + return true; +} + +void FileA3D::appendToFile(ObjectBase *obj) { + if(!obj) { + return; + } + if(!mWriteStream) { + const uint64_t initialStreamSize = 256*1024; + mWriteStream = new OStream(initialStreamSize, false); } - ie->mRsObj = m; + A3DIndexEntry *indexEntry = new A3DIndexEntry(); + indexEntry->mObjectName.setTo(obj->getName()); + indexEntry->mType = obj->getClassId(); + indexEntry->mOffset = mWriteStream->getPos(); + indexEntry->mRsObj = obj; + mWriteIndex.push(indexEntry); + obj->serialize(mWriteStream); + indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset; + mWriteStream->align(4); } -void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie) +namespace android { +namespace renderscript { + +void rsi_FileA3DGetNumIndexEntries(Context *rsc, int32_t *numEntries, RsFile file) { - Mesh::Primitive_t * p = new Mesh::Primitive_t; + FileA3D *fa3d = static_cast<FileA3D *>(file); - p->mIndexCount = io->loadU32(); - uint32_t vertIdx = io->loadU32(); - p->mRestartCounts = io->loadU16(); - uint32_t bits = io->loadU8(); - p->mType = (RsPrimitive)io->loadU8(); + if(fa3d) { + *numEntries = fa3d->getNumIndexEntries(); + } + else { + *numEntries = 0; + } +} - LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits); +void rsi_FileA3DGetIndexEntries(Context *rsc, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) +{ + FileA3D *fa3d = static_cast<FileA3D *>(file); - p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj; + if(!fa3d) { + LOGE("Can't load index entries. No valid file"); + return; + } - p->mIndicies = new uint16_t[p->mIndexCount]; - for (uint32_t ct = 0; ct < p->mIndexCount; ct++) { - switch(bits) { - case 8: - p->mIndicies[ct] = io->loadU8(); - break; - case 16: - p->mIndicies[ct] = io->loadU16(); - break; - case 32: - p->mIndicies[ct] = io->loadU32(); - break; - } - LOGE(" idx %i", p->mIndicies[ct]); - } - - if (p->mRestartCounts) { - p->mRestarts = new uint16_t[p->mRestartCounts]; - for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) { - switch(bits) { - case 8: - p->mRestarts[ct] = io->loadU8(); - break; - case 16: - p->mRestarts[ct] = io->loadU16(); - break; - case 32: - p->mRestarts[ct] = io->loadU32(); - break; - } - LOGE(" idx %i", p->mRestarts[ct]); - } - } else { - p->mRestarts = NULL; + uint32_t numFileEntries = fa3d->getNumIndexEntries(); + if(numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) { + LOGE("Can't load index entries. Invalid number requested"); + return; } - ie->mRsObj = p; -} + for(uint32_t i = 0; i < numFileEntries; i ++) { + const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i); + fileEntries[i].classID = entry->getType(); + fileEntries[i].objectName = entry->getObjectName().string(); + } -void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie) -{ - Mesh::Verticies_t *cv = new Mesh::Verticies_t; - cv->mAllocationCount = io->loadU32(); - cv->mAllocations = new Allocation *[cv->mAllocationCount]; - LOGE("processChunk_Verticies count %i", cv->mAllocationCount); - for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) { - uint32_t i = io->loadU32(); - cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj; - LOGE(" idx %i", i); - } - ie->mRsObj = cv; } -void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie) +RsObjectBase rsi_FileA3DGetEntryByIndex(Context *rsc, uint32_t index, RsFile file) { - /* - rsi_ElementBegin(rsc); - - uint32_t count = io->loadU32(); - LOGE("processChunk_Element count %i", count); - while (count--) { - RsDataKind dk = (RsDataKind)io->loadU8(); - RsDataType dt = (RsDataType)io->loadU8(); - uint32_t bits = io->loadU8(); - bool isNorm = io->loadU8() != 0; - LOGE(" %i %i %i %i", dk, dt, bits, isNorm); - rsi_ElementAdd(rsc, dk, dt, isNorm, bits, 0); - } - LOGE("processChunk_Element create"); - ie->mRsObj = rsi_ElementCreate(rsc); - */ + FileA3D *fa3d = static_cast<FileA3D *>(file); + if(!fa3d) { + LOGE("Can't load entry. No valid file"); + return NULL; + } + + ObjectBase *obj = fa3d->initializeFromEntry(index); + LOGV("Returning object with name %s", obj->getName()); + + return obj; } -void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie) +RsFile rsi_FileA3DCreateFromAssetStream(Context *rsc, const void *data, uint32_t len) { - uint32_t index = io->loadU32(); - uint32_t count = io->loadU32(); - - LOGE("processChunk_ElementSource count %i, index %i", count, index); + if (data == NULL) { + LOGE("File load failed. Asset stream is NULL"); + return NULL; + } - RsElement e = (RsElement)mIndex[index].mRsObj; + FileA3D *fa3d = new FileA3D(rsc); - RsAllocation a = rsi_AllocationCreateSized(rsc, e, count); - Allocation * alloc = static_cast<Allocation *>(a); + fa3d->load(data, len); + fa3d->incUserRef(); - float * data = (float *)alloc->getPtr(); - while(count--) { - *data = io->loadF(); - LOGE(" %f", *data); - data++; - } - ie->mRsObj = alloc; + return fa3d; } -namespace android { -namespace renderscript { - RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len) { - FileA3D *fa3d = new FileA3D; + FileA3D *fa3d = new FileA3D(rsc); FILE *f = fopen("/sdcard/test.a3d", "rb"); if (f) { - fa3d->load(rsc, f); + fa3d->load(f); fclose(f); + fa3d->incUserRef(); return fa3d; } delete fa3d; diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h index 9ee08ec..b985907 100644 --- a/libs/rs/rsFileA3D.h +++ b/libs/rs/rsFileA3D.h @@ -18,20 +18,23 @@ #define ANDROID_RS_FILE_A3D_H #include "RenderScript.h" -#include "rsFileA3DDecls.h" #include "rsMesh.h" #include <utils/String8.h> +#include "rsStream.h" #include <stdio.h> +#define A3D_MAGIC_KEY "Android3D_ff" + // --------------------------------------------------------------------------- namespace android { + namespace renderscript { -class FileA3D +class FileA3D : public ObjectBase { public: - FileA3D(); + FileA3D(Context *rsc); ~FileA3D(); uint32_t mMajorVersion; @@ -40,78 +43,53 @@ public: uint64_t mStringTableOffset; bool mUse64BitOffsets; - struct A3DIndexEntry { - String8 mID; - A3DChunkType mType; + class A3DIndexEntry { + String8 mObjectName; + RsA3DClassID mType; uint64_t mOffset; - void * mRsObj; - }; - - bool load(Context *rsc, FILE *f); - -protected: - class IO - { + uint64_t mLength; + ObjectBase *mRsObj; public: - IO(const uint8_t *, bool use64); - - float loadF() { - mPos = (mPos + 3) & (~3); - float tmp = reinterpret_cast<const float *>(&mData[mPos])[0]; - mPos += sizeof(float); - return tmp; - } - int32_t loadI32() { - mPos = (mPos + 3) & (~3); - int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0]; - mPos += sizeof(int32_t); - return tmp; + friend class FileA3D; + const String8 &getObjectName() const { + return mObjectName; } - uint32_t loadU32() { - mPos = (mPos + 3) & (~3); - uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0]; - mPos += sizeof(uint32_t); - return tmp; + RsA3DClassID getType() const { + return mType; } - uint16_t loadU16() { - mPos = (mPos + 1) & (~1); - uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0]; - mPos += sizeof(uint16_t); - return tmp; - } - uint8_t loadU8() { - uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0]; - mPos += sizeof(uint8_t); - return tmp; - } - uint64_t loadOffset(); - void loadString(String8 *s); - uint64_t getPos() const {return mPos;} - const uint8_t * getPtr() const; - protected: - const uint8_t * mData; - uint64_t mPos; - bool mUse64; }; + bool load(FILE *f); + bool load(const void *data, size_t length); + + size_t getNumIndexEntries() const; + const A3DIndexEntry* getIndexEntry(size_t index) const; + ObjectBase *initializeFromEntry(size_t index); + + void appendToFile(ObjectBase *obj); + bool writeFile(const char *filename); + + // Currently files do not get serialized, + // but we need to inherit from ObjectBase for ref tracking + virtual void serialize(OStream *stream) const { + } + virtual RsA3DClassID getClassId() const { + return RS_A3D_CLASS_ID_UNKNOWN; + } + +protected: - bool process(Context *rsc); - bool processIndex(Context *rsc, A3DIndexEntry *); - void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie); - void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie); - void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie); - void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie); - void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie); + void parseHeader(IStream *headerStream); const uint8_t * mData; void * mAlloc; uint64_t mDataSize; - Context * mRsc; - Vector<A3DIndexEntry> mIndex; - Vector<String8> mStrings; - Vector<uint32_t> mStringIndexValues; + OStream *mWriteStream; + Vector<A3DIndexEntry*> mWriteIndex; + IStream *mReadStream; + Vector<A3DIndexEntry*> mIndex; }; diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp new file mode 100644 index 0000000..8756f82 --- /dev/null +++ b/libs/rs/rsFont.cpp @@ -0,0 +1,891 @@ + +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif + +#include "rsFont.h" +#include "rsProgramFragment.h" +#include <cutils/properties.h> +#include FT_BITMAP_H + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) +{ + mAllocFile = __FILE__; + mAllocLine = __LINE__; + mInitialized = false; + mHasKerning = false; + mFace = NULL; +} + +bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) +{ + if(mInitialized) { + LOGE("Reinitialization of fonts not supported"); + return false; + } + + String8 fontsDir("/fonts/"); + String8 fullPath(getenv("ANDROID_ROOT")); + fullPath += fontsDir; + fullPath += name; + + FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace); + if(error) { + LOGE("Unable to initialize font %s", fullPath.string()); + return false; + } + + mFontName = name; + mFontSize = fontSize; + mDpi = dpi; + + error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0); + if(error) { + LOGE("Unable to set font size on %s", fullPath.string()); + return false; + } + + mHasKerning = FT_HAS_KERNING(mFace); + + mInitialized = true; + return true; +} + +void Font::invalidateTextureCache() +{ + for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { + mCachedGlyphs.valueAt(i)->mIsValid = false; + } +} + +void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) +{ + FontState *state = &mRSC->mStateFont; + + int32_t nPenX = x + glyph->mBitmapLeft; + int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; + + float u1 = glyph->mBitmapMinU; + float u2 = glyph->mBitmapMaxU; + float v1 = glyph->mBitmapMinV; + float v2 = glyph->mBitmapMaxV; + + int32_t width = (int32_t) glyph->mBitmapWidth; + int32_t height = (int32_t) glyph->mBitmapHeight; + + state->appendMeshQuad(nPenX, nPenY, 0, u1, v2, + nPenX + width, nPenY, 0, u2, v2, + nPenX + width, nPenY - height, 0, u2, v1, + nPenX, nPenY - height, 0, u1, v1); +} + +void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { + int32_t nPenX = x + glyph->mBitmapLeft; + int32_t nPenY = y + glyph->mBitmapTop; + + uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth; + uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight; + + FontState *state = &mRSC->mStateFont; + uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); + const uint8_t* cacheBuffer = state->getTextTextureData(); + + uint32_t cacheX = 0, cacheY = 0; + int32_t bX = 0, bY = 0; + for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) { + for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) { + if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { + LOGE("Skipping invalid index"); + continue; + } + uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; + bitmap[bY * bitmapW + bX] = tempCol; + } + } + +} + +void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) { + int32_t nPenX = x + glyph->mBitmapLeft; + int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; + + int32_t width = (int32_t) glyph->mBitmapWidth; + int32_t height = (int32_t) glyph->mBitmapHeight; + + if (bounds->bottom > nPenY) { + bounds->bottom = nPenY; + } + if (bounds->left > nPenX) { + bounds->left = nPenX; + } + if (bounds->right < nPenX + width) { + bounds->right = nPenX + width; + } + if (bounds->top < nPenY + height) { + bounds->top = nPenY + height; + } +} + +void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y, + uint32_t start, int32_t numGlyphs, + RenderMode mode, Rect *bounds, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) +{ + if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) { + return; + } + + if(mode == Font::MEASURE) { + if (bounds == NULL) { + LOGE("No return rectangle provided to measure text"); + return; + } + // Reset min and max of the bounding box to something large + bounds->set(1e6, -1e6, -1e6, 1e6); + } + + int32_t penX = x, penY = y; + int32_t glyphsLeft = 1; + if(numGlyphs > 0) { + glyphsLeft = numGlyphs; + } + + size_t index = start; + size_t nextIndex = 0; + + while (glyphsLeft > 0) { + + int32_t utfChar = utf32_at(text, len, index, &nextIndex); + + // Reached the end of the string or encountered + if(utfChar < 0) { + break; + } + + // Move to the next character in the array + index = nextIndex; + + CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar); + + // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage + if(cachedGlyph->mIsValid) { + switch(mode) { + case FRAMEBUFFER: + drawCachedGlyph(cachedGlyph, penX, penY); + break; + case BITMAP: + drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH); + break; + case MEASURE: + measureCachedGlyph(cachedGlyph, penX, penY, bounds); + break; + } + } + + penX += (cachedGlyph->mAdvance.x >> 6); + + // If we were given a specific number of glyphs, decrement + if(numGlyphs > 0) { + glyphsLeft --; + } + } +} + +Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { + + CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar); + if(cachedGlyph == NULL) { + cachedGlyph = cacheGlyph((uint32_t)utfChar); + } + // Is the glyph still in texture cache? + if(!cachedGlyph->mIsValid) { + updateGlyphCache(cachedGlyph); + } + + return cachedGlyph; +} + +void Font::updateGlyphCache(CachedGlyphInfo *glyph) +{ + FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); + if(error) { + LOGE("Couldn't load glyph."); + return; + } + + glyph->mAdvance = mFace->glyph->advance; + glyph->mBitmapLeft = mFace->glyph->bitmap_left; + glyph->mBitmapTop = mFace->glyph->bitmap_top; + + FT_Bitmap *bitmap = &mFace->glyph->bitmap; + + // Now copy the bitmap into the cache texture + uint32_t startX = 0; + uint32_t startY = 0; + + // Let the font state figure out where to put the bitmap + FontState *state = &mRSC->mStateFont; + glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY); + + if(!glyph->mIsValid) { + return; + } + + uint32_t endX = startX + bitmap->width; + uint32_t endY = startY + bitmap->rows; + + glyph->mBitmapMinX = startX; + glyph->mBitmapMinY = startY; + glyph->mBitmapWidth = bitmap->width; + glyph->mBitmapHeight = bitmap->rows; + + uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); + uint32_t cacheHeight = state->getCacheTextureType()->getDimY(); + + glyph->mBitmapMinU = (float)startX / (float)cacheWidth; + glyph->mBitmapMinV = (float)startY / (float)cacheHeight; + glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; + glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; +} + +Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) +{ + CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); + mCachedGlyphs.add(glyph, newGlyph); + + newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); + newGlyph->mIsValid = false; + + updateGlyphCache(newGlyph); + + return newGlyph; +} + +Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) +{ + rsc->mStateFont.checkInit(); + Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; + + for(uint32_t i = 0; i < activeFonts.size(); i ++) { + Font *ithFont = activeFonts[i]; + if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) { + return ithFont; + } + } + + Font *newFont = new Font(rsc); + bool isInitialized = newFont->init(name, fontSize, dpi); + if(isInitialized) { + activeFonts.push(newFont); + rsc->mStateFont.precacheLatin(newFont); + return newFont; + } + + delete newFont; + return NULL; + +} + +Font::~Font() +{ + if(mFace) { + FT_Done_Face(mFace); + } + + for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { + if (mRSC->mStateFont.mActiveFonts[ct] == this) { + mRSC->mStateFont.mActiveFonts.removeAt(ct); + break; + } + } + + for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { + CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); + delete glyph; + } +} + +FontState::FontState() +{ + mInitialized = false; + mMaxNumberOfQuads = 1024; + mCurrentQuadIndex = 0; + mRSC = NULL; + mLibrary = NULL; + + // Get the renderer properties + char property[PROPERTY_VALUE_MAX]; + + // Get the gamma + float gamma = DEFAULT_TEXT_GAMMA; + if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { + LOGD(" Setting text gamma to %s", property); + gamma = atof(property); + } else { + LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); + } + + // Get the black gamma threshold + int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; + if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { + LOGD(" Setting text black gamma threshold to %s", property); + blackThreshold = atoi(property); + } else { + LOGD(" Using default text black gamma threshold of %d", + DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); + } + mBlackThreshold = (float)(blackThreshold) / 255.0f; + + // Get the white gamma threshold + int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; + if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { + LOGD(" Setting text white gamma threshold to %s", property); + whiteThreshold = atoi(property); + } else { + LOGD(" Using default white black gamma threshold of %d", + DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); + } + mWhiteThreshold = (float)(whiteThreshold) / 255.0f; + + // Compute the gamma tables + mBlackGamma = gamma; + mWhiteGamma = 1.0f / gamma; + + setFontColor(0.1f, 0.1f, 0.1f, 1.0f); +} + +FontState::~FontState() +{ + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + delete mCacheLines[i]; + } + + rsAssert(!mActiveFonts.size()); +} + +FT_Library FontState::getLib() +{ + if(!mLibrary) { + FT_Error error = FT_Init_FreeType(&mLibrary); + if(error) { + LOGE("Unable to initialize freetype"); + return NULL; + } + } + + return mLibrary; +} + +void FontState::init(Context *rsc) +{ + mRSC = rsc; +} + +void FontState::flushAllAndInvalidate() +{ + if(mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } + for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { + mActiveFonts[i]->invalidateTextureCache(); + } + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + mCacheLines[i]->mCurrentCol = 0; + } +} + +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) { + LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); + return false; + } + + // Now copy the bitmap into the cache texture + uint32_t startX = 0; + uint32_t startY = 0; + + bool bitmapFit = false; + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); + if(bitmapFit) { + break; + } + } + + // If the new glyph didn't fit, flush the state so far and invalidate everything + if(!bitmapFit) { + flushAllAndInvalidate(); + + // Try to fit it again + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); + if(bitmapFit) { + break; + } + } + + // if we still don't fit, something is wrong and we shouldn't draw + if(!bitmapFit) { + LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); + return false; + } + } + + *retOriginX = startX; + *retOriginY = startY; + + uint32_t endX = startX + bitmap->width; + uint32_t endY = startY + bitmap->rows; + + uint32_t cacheWidth = getCacheTextureType()->getDimX(); + + uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr(); + uint8_t *bitmapBuffer = bitmap->buffer; + + uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; + for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { + for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { + uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX]; + cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; + } + } + + // This will dirty the texture and the shader so next time + // we draw it will upload the data + mTextTexture->deferedUploadToTexture(mRSC, false, 0); + mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get()); + + // Some debug code + /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + LOGE("Cache Line: H: %u Empty Space: %f", + mCacheLines[i]->mMaxHeight, + (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); + + }*/ + + return true; +} + +void FontState::initRenderState() +{ + String8 shaderString("varying vec2 varTex0;\n"); + shaderString.append("void main() {\n"); + shaderString.append(" lowp vec4 col = UNI_Color;\n"); + shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"); + shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n"); + shaderString.append(" gl_FragColor = col;\n"); + shaderString.append("}\n"); + + const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); + const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1); + mRSC->mStateElement.elementBuilderBegin(); + mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1); + mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1); + const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC); + + Type *inputType = new Type(mRSC); + inputType->setElement(constInput); + inputType->setDimX(1); + inputType->compute(); + + uint32_t tmp[4]; + tmp[0] = RS_PROGRAM_PARAM_CONSTANT; + tmp[1] = (uint32_t)inputType; + tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; + tmp[3] = 1; + + mFontShaderFConstant.set(new Allocation(mRSC, inputType)); + ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), + shaderString.length(), tmp, 4); + mFontShaderF.set(pf); + mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0); + + Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, + RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); + mFontSampler.set(sampler); + mFontShaderF->bindSampler(mRSC, 0, sampler); + + ProgramStore *fontStore = new ProgramStore(mRSC); + 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); +} + +void FontState::initTextTexture() +{ + const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); + + // We will allocate a texture to initially hold 32 character bitmaps + Type *texType = new Type(mRSC); + texType->setElement(alphaElem); + texType->setDimX(1024); + texType->setDimY(256); + texType->compute(); + + Allocation *cacheAlloc = new Allocation(mRSC, texType); + mTextTexture.set(cacheAlloc); + mTextTexture->deferedUploadToTexture(mRSC, false, 0); + + // Split up our cache texture into lines of certain widths + int32_t nextLine = 0; + mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); +} + +// Avoid having to reallocate memory and render quad by quad +void FontState::initVertexArrayBuffers() +{ + // Now lets write index data + const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); + Type *indexType = new Type(mRSC); + uint32_t numIndicies = mMaxNumberOfQuads * 6; + indexType->setDimX(numIndicies); + indexType->setElement(indexElem); + indexType->compute(); + + Allocation *indexAlloc = new Allocation(mRSC, indexType); + uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); + + // Four verts, two triangles , six indices per quad + for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { + int32_t i6 = i * 6; + int32_t i4 = i * 4; + + indexPtr[i6 + 0] = i4 + 0; + indexPtr[i6 + 1] = i4 + 1; + indexPtr[i6 + 2] = i4 + 2; + + indexPtr[i6 + 3] = i4 + 0; + indexPtr[i6 + 4] = i4 + 2; + indexPtr[i6 + 5] = i4 + 3; + } + + indexAlloc->deferedUploadToBufferObject(mRSC); + mIndexBuffer.set(indexAlloc); + + 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); + + const Element *elemArray[2]; + elemArray[0] = posElem; + elemArray[1] = texElem; + + String8 posName("position"); + String8 texName("texture0"); + + const char *nameArray[2]; + nameArray[0] = posName.string(); + nameArray[1] = texName.string(); + size_t lengths[2]; + lengths[0] = posName.size(); + lengths[1] = texName.size(); + uint32_t arraySizes[2] = {1, 1}; + + const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes); + + Type *vertexDataType = new Type(mRSC); + vertexDataType->setDimX(mMaxNumberOfQuads * 4); + vertexDataType->setElement(vertexDataElem); + vertexDataType->compute(); + + Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); + mTextMeshPtr = (float*)vertexAlloc->getPtr(); + + mVertexArray.set(vertexAlloc); +} + +// We don't want to allocate anything unless we actually draw text +void FontState::checkInit() +{ + if(mInitialized) { + return; + } + + initTextTexture(); + initRenderState(); + + initVertexArrayBuffers(); + + // We store a string with letters in a rough frequency of occurrence + mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); + mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); + mLatinPrecache += String8(",.?!()-+@;:`'"); + mLatinPrecache += String8("0123456789"); + + mInitialized = true; +} + +void FontState::issueDrawCommand() { + + ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); + mRSC->setVertex(mRSC->getDefaultProgramVertex()); + + ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); + mRSC->setRaster(mRSC->getDefaultProgramRaster()); + + ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); + mRSC->setFragment(mFontShaderF.get()); + + ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); + mRSC->setFragmentStore(mFontProgramStore.get()); + + if(mConstantsDirty) { + mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants)); + mConstantsDirty = false; + } + + if (!mRSC->setupCheck()) { + mRSC->setVertex((ProgramVertex *)tmpV.get()); + mRSC->setRaster((ProgramRaster *)tmpR.get()); + mRSC->setFragment((ProgramFragment *)tmpF.get()); + mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); + return; + } + + float *vtx = (float*)mVertexArray->getPtr(); + float *tex = vtx + 3; + + VertexArray va; + va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position"); + va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0"); + 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)); + + // Reset the state + mRSC->setVertex((ProgramVertex *)tmpV.get()); + mRSC->setRaster((ProgramRaster *)tmpR.get()); + mRSC->setFragment((ProgramFragment *)tmpF.get()); + mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); +} + +void FontState::appendMeshQuad(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) +{ + const uint32_t vertsPerQuad = 4; + const uint32_t floatsPerVert = 5; + float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; + + // Cull things that are off the screen + float width = (float)mRSC->getWidth(); + float height = (float)mRSC->getHeight(); + + if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { + return; + } + + /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); + LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); + LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); + LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ + + (*currentPos++) = x1; + (*currentPos++) = y1; + (*currentPos++) = z1; + (*currentPos++) = u1; + (*currentPos++) = v1; + + (*currentPos++) = x2; + (*currentPos++) = y2; + (*currentPos++) = z2; + (*currentPos++) = u2; + (*currentPos++) = v2; + + (*currentPos++) = x3; + (*currentPos++) = y3; + (*currentPos++) = z3; + (*currentPos++) = u3; + (*currentPos++) = v3; + + (*currentPos++) = x4; + (*currentPos++) = y4; + (*currentPos++) = z4; + (*currentPos++) = u4; + (*currentPos++) = v4; + + mCurrentQuadIndex ++; + + if(mCurrentQuadIndex == mMaxNumberOfQuads) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +uint32_t FontState::getRemainingCacheCapacity() { + uint32_t remainingCapacity = 0; + uint32_t totalPixels = 0; + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); + totalPixels += mCacheLines[i]->mMaxWidth; + } + remainingCapacity = (remainingCapacity * 100) / totalPixels; + return remainingCapacity; +} + +void FontState::precacheLatin(Font *font) { + // Remaining capacity is measured in % + uint32_t remainingCapacity = getRemainingCacheCapacity(); + uint32_t precacheIdx = 0; + while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { + font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); + remainingCapacity = getRemainingCacheCapacity(); + precacheIdx ++; + } +} + + +void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y, + uint32_t startIndex, int32_t numGlyphs, + Font::RenderMode mode, + Font::Rect *bounds, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) +{ + checkInit(); + + // Render code here + Font *currentFont = mRSC->getFont(); + if(!currentFont) { + if(!mDefault.get()) { + mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); + } + currentFont = mDefault.get(); + } + if(!currentFont) { + LOGE("Unable to initialize any fonts"); + return; + } + + currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs, + mode, bounds, bitmap, bitmapW, bitmapH); + + if(mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) { + renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds); +} + +void FontState::setFontColor(float r, float g, float b, float a) { + mConstants.mFontColor[0] = r; + mConstants.mFontColor[1] = g; + mConstants.mFontColor[2] = b; + mConstants.mFontColor[3] = a; + + mConstants.mGamma = 1.0f; + const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f; + if (luminance <= mBlackThreshold) { + mConstants.mGamma = mBlackGamma; + } else if (luminance >= mWhiteThreshold) { + mConstants.mGamma = mWhiteGamma; + } + + mConstantsDirty = true; +} + +void FontState::getFontColor(float *r, float *g, float *b, float *a) const { + *r = mConstants.mFontColor[0]; + *g = mConstants.mFontColor[1]; + *b = mConstants.mFontColor[2]; + *a = mConstants.mFontColor[3]; +} + +void FontState::deinit(Context *rsc) +{ + mInitialized = false; + + mFontShaderFConstant.clear(); + + mIndexBuffer.clear(); + mVertexArray.clear(); + + mFontShaderF.clear(); + mFontSampler.clear(); + mFontProgramStore.clear(); + + mTextTexture.clear(); + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + delete mCacheLines[i]; + } + mCacheLines.clear(); + + mDefault.clear(); + + Vector<Font*> fontsToDereference = mActiveFonts; + for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { + fontsToDereference[i]->zeroUserRef(); + } + + if(mLibrary) { + FT_Done_FreeType( mLibrary ); + mLibrary = NULL; + } +} + +namespace android { +namespace renderscript { + +RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) +{ + Font *newFont = Font::create(rsc, name, fontSize, dpi); + if(newFont) { + newFont->incUserRef(); + } + return newFont; +} + +} // renderscript +} // android diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h new file mode 100644 index 0000000..0012b84 --- /dev/null +++ b/libs/rs/rsFont.h @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_FONT_H +#define ANDROID_RS_FONT_H + +#include "RenderScript.h" +#include "rsStream.h" +#include <utils/String8.h> +#include <utils/Vector.h> +#include <utils/KeyedVector.h> + +#include <ft2build.h> +#include FT_FREETYPE_H + +// --------------------------------------------------------------------------- +namespace android { + +namespace renderscript { + +// Gamma (>= 1.0, <= 10.0) +#define PROPERTY_TEXT_GAMMA "ro.text_gamma" +#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold" +#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold" + +#define DEFAULT_TEXT_GAMMA 1.4f +#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64 +#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192 + +class FontState; + +class Font : public ObjectBase +{ +public: + enum RenderMode { + FRAMEBUFFER, + BITMAP, + MEASURE, + }; + + struct Rect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + void set(int32_t l, int32_t r, int32_t t, int32_t b) { + left = l; + right = r; + top = t; + bottom = b; + } + }; + + ~Font(); + + // Currently files do not get serialized, + // but we need to inherit from ObjectBase for ref tracking + virtual void serialize(OStream *stream) const { + } + virtual RsA3DClassID getClassId() const { + return RS_A3D_CLASS_ID_UNKNOWN; + } + + static Font * create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi); + +protected: + + friend class FontState; + + // Pointer to the utf data, length of data, where to start, number of glyphs ot read + // (each glyph may be longer than a char because we are dealing with utf data) + // Last two variables are the initial pen position + void renderUTF(const char *text, uint32_t len, int32_t x, int32_t y, + uint32_t start, int32_t numGlyphs, + RenderMode mode = FRAMEBUFFER, Rect *bounds = NULL, + uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0); + + void invalidateTextureCache(); + struct CachedGlyphInfo + { + // Has the cache been invalidated? + bool mIsValid; + // Location of the cached glyph in the bitmap + // in case we need to resize the texture + uint32_t mBitmapMinX; + uint32_t mBitmapMinY; + uint32_t mBitmapWidth; + uint32_t mBitmapHeight; + // Also cache texture coords for the quad + float mBitmapMinU; + float mBitmapMinV; + float mBitmapMaxU; + float mBitmapMaxV; + // Minimize how much we call freetype + FT_UInt mGlyphIndex; + FT_Vector mAdvance; + // Values below contain a glyph's origin in the bitmap + FT_Int mBitmapLeft; + FT_Int mBitmapTop; + }; + + String8 mFontName; + uint32_t mFontSize; + uint32_t mDpi; + + Font(Context *rsc); + bool init(const char *name, uint32_t fontSize, uint32_t dpi); + + FT_Face mFace; + bool mInitialized; + bool mHasKerning; + + DefaultKeyedVector<uint32_t, CachedGlyphInfo* > mCachedGlyphs; + CachedGlyphInfo* getCachedUTFChar(int32_t utfChar); + + CachedGlyphInfo *cacheGlyph(uint32_t glyph); + void updateGlyphCache(CachedGlyphInfo *glyph); + void measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds); + void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y); + void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH); +}; + +class FontState +{ +public: + FontState(); + ~FontState(); + + void init(Context *rsc); + void deinit(Context *rsc); + + ObjectBaseRef<Font> mDefault; + ObjectBaseRef<Font> mLast; + + void renderText(const char *text, uint32_t len, int32_t x, int32_t y, + uint32_t startIndex = 0, int numGlyphs = -1, + Font::RenderMode mode = Font::FRAMEBUFFER, + Font::Rect *bounds = NULL, + uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0); + + void measureText(const char *text, uint32_t len, Font::Rect *bounds); + + void setFontColor(float r, float g, float b, float a); + void getFontColor(float *r, float *g, float *b, float *a) const; + +protected: + + friend class Font; + + struct CacheTextureLine + { + uint32_t mMaxHeight; + uint32_t mMaxWidth; + uint32_t mCurrentRow; + uint32_t mCurrentCol; + bool mDirty; + + CacheTextureLine(uint32_t maxHeight, uint32_t maxWidth, uint32_t currentRow, uint32_t currentCol) : + mMaxHeight(maxHeight), mMaxWidth(maxWidth), mCurrentRow(currentRow), mCurrentCol(currentCol), + mDirty(false) { + } + + bool fitBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) { + if((uint32_t)bitmap->rows > mMaxHeight) { + return false; + } + + if(mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) { + *retOriginX = mCurrentCol; + *retOriginY = mCurrentRow; + mCurrentCol += bitmap->width; + mDirty = true; + return true; + } + + return false; + } + }; + + Vector<CacheTextureLine*> mCacheLines; + uint32_t getRemainingCacheCapacity(); + + void precacheLatin(Font *font); + String8 mLatinPrecache; + + Context *mRSC; + + struct { + float mFontColor[4]; + float mGamma; + } mConstants; + bool mConstantsDirty; + + float mBlackGamma; + float mWhiteGamma; + + float mBlackThreshold; + float mWhiteThreshold; + + // Free type library, we only need one copy + FT_Library mLibrary; + FT_Library getLib(); + Vector<Font*> mActiveFonts; + + // Render state for the font + ObjectBaseRef<Allocation> mFontShaderFConstant; + ObjectBaseRef<ProgramFragment> mFontShaderF; + ObjectBaseRef<Sampler> mFontSampler; + ObjectBaseRef<ProgramStore> mFontProgramStore; + void initRenderState(); + + // Texture to cache glyph bitmaps + ObjectBaseRef<Allocation> mTextTexture; + void initTextTexture(); + const uint8_t* getTextTextureData() const { + return (uint8_t*)mTextTexture->getPtr(); + } + + bool cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY); + const Type* getCacheTextureType() { + return mTextTexture->getType(); + } + + void flushAllAndInvalidate(); + + // Pointer to vertex data to speed up frame to frame work + float *mTextMeshPtr; + uint32_t mCurrentQuadIndex; + uint32_t mMaxNumberOfQuads; + + void initVertexArrayBuffers(); + ObjectBaseRef<Allocation> mIndexBuffer; + ObjectBaseRef<Allocation> mVertexArray; + + + bool mInitialized; + + void checkInit(); + + void issueDrawCommand(); + + void appendMeshQuad(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); + +}; + + +} +} + +#endif diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h index 800eddd..c02fd42 100644 --- a/libs/rs/rsHandcode.h +++ b/libs/rs/rsHandcode.h @@ -1,6 +1,57 @@ #define DATA_SYNC_SIZE 1024 +static inline void rsHCAPI_ContextFinish (RsContext rsc) +{ + ThreadIO *io = &((Context *)rsc)->mIO; + uint32_t size = sizeof(RS_CMD_ContextFinish); + RS_CMD_ContextFinish *cmd = static_cast<RS_CMD_ContextFinish *>(io->mToCore.reserve(size)); + 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_AllocationData (RsContext rsc, RsAllocation va, const void * data, uint32_t sizeBytes) { ThreadIO *io = &((Context *)rsc)->mIO; @@ -45,3 +96,26 @@ static inline void rsHCAPI_Allocation1DSubData (RsContext rsc, RsAllocation va, } +static inline void rsHCAPI_Allocation1DSubElementData (RsContext rsc, RsAllocation va, uint32_t x, const void * data, uint32_t comp_offset, uint32_t sizeBytes) +{ + ThreadIO *io = &((Context *)rsc)->mIO; + uint32_t size = sizeof(RS_CMD_Allocation1DSubElementData); + if (sizeBytes < DATA_SYNC_SIZE) { + size += (sizeBytes + 3) & ~3; + } + RS_CMD_Allocation1DSubElementData *cmd = static_cast<RS_CMD_Allocation1DSubElementData *>(io->mToCore.reserve(size)); + cmd->va = va; + cmd->x = x; + 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_Allocation1DSubElementData, size); + } else { + io->mToCore.commitSync(RS_CMD_ID_Allocation1DSubElementData, size); + } + +} + diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp deleted file mode 100644 index 6f2cf3e..0000000 --- a/libs/rs/rsLight.cpp +++ /dev/null @@ -1,130 +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 "rsContext.h" - -#include <GLES/gl.h> - -using namespace android; -using namespace android::renderscript; - - -Light::Light(Context *rsc, bool isLocal, bool isMono) : ObjectBase(rsc) -{ - mAllocFile = __FILE__; - mAllocLine = __LINE__; - mIsLocal = isLocal; - mIsMono = isMono; - - mPosition[0] = 0; - mPosition[1] = 0; - mPosition[2] = 1; - mPosition[3] = 0; - - mColor[0] = 1.f; - mColor[1] = 1.f; - mColor[2] = 1.f; - mColor[3] = 1.f; -} - -Light::~Light() -{ -} - -void Light::setPosition(float x, float y, float z) -{ - mPosition[0] = x; - mPosition[1] = y; - mPosition[2] = z; -} - -void Light::setColor(float r, float g, float b) -{ - mColor[0] = r; - mColor[1] = g; - mColor[2] = b; -} - -void Light::setupGL(uint32_t num) const -{ - glLightfv(GL_LIGHT0 + num, GL_DIFFUSE, mColor); - glLightfv(GL_LIGHT0 + num, GL_SPECULAR, mColor); - glLightfv(GL_LIGHT0 + num, GL_POSITION, mPosition); -} - -//////////////////////////////////////////// - -LightState::LightState() -{ - clear(); -} - -LightState::~LightState() -{ -} - -void LightState::clear() -{ - mIsLocal = false; - mIsMono = false; -} - - -//////////////////////////////////////////////////// -// - -namespace android { -namespace renderscript { - -void rsi_LightBegin(Context *rsc) -{ - rsc->mStateLight.clear(); -} - -void rsi_LightSetLocal(Context *rsc, bool isLocal) -{ - rsc->mStateLight.mIsLocal = isLocal; -} - -void rsi_LightSetMonochromatic(Context *rsc, bool isMono) -{ - rsc->mStateLight.mIsMono = isMono; -} - -RsLight rsi_LightCreate(Context *rsc) -{ - Light *l = new Light(rsc, rsc->mStateLight.mIsLocal, - rsc->mStateLight.mIsMono); - l->incUserRef(); - return l; -} - -void rsi_LightSetColor(Context *rsc, RsLight vl, float r, float g, float b) -{ - Light *l = static_cast<Light *>(vl); - l->setColor(r, g, b); -} - -void rsi_LightSetPosition(Context *rsc, RsLight vl, float x, float y, float z) -{ - Light *l = static_cast<Light *>(vl); - l->setPosition(x, y, z); -} - - - -} -} diff --git a/libs/rs/rsLight.h b/libs/rs/rsLight.h deleted file mode 100644 index d8796e6..0000000 --- a/libs/rs/rsLight.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_LIGHT_H -#define ANDROID_LIGHT_H - - -#include "rsObjectBase.h" - -// --------------------------------------------------------------------------- -namespace android { -namespace renderscript { - - -// An element is a group of Components that occupies one cell in a structure. -class Light : public ObjectBase -{ -public: - Light(Context *, bool isLocal, bool isMono); - virtual ~Light(); - - // Values, mutable after creation. - void setPosition(float x, float y, float z); - void setColor(float r, float g, float b); - - void setupGL(uint32_t num) const; - -protected: - float mColor[4]; - float mPosition[4]; - bool mIsLocal; - bool mIsMono; -}; - - -class LightState { -public: - LightState(); - ~LightState(); - - void clear(); - - bool mIsMono; - bool mIsLocal; -}; - - -} -} -#endif //ANDROID_LIGHT_H - diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp index c796520..10b38af 100644 --- a/libs/rs/rsLocklessFifo.cpp +++ b/libs/rs/rsLocklessFifo.cpp @@ -15,9 +15,11 @@ */ #include "rsLocklessFifo.h" +#include "utils/Timers.h" +#include "utils/StopWatch.h" using namespace android; - +using namespace android::renderscript; LocklessCommandFifo::LocklessCommandFifo() { @@ -115,6 +117,10 @@ void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes) if (mInShutdown) { return; } + + //char buf[1024]; + //sprintf(buf, "RenderScript LocklessCommandFifo::commitSync %p %i %i", this, command, sizeInBytes); + //StopWatch compileTimer(buf); commit(command, sizeInBytes); flush(); } @@ -128,15 +134,19 @@ void LocklessCommandFifo::flush() //dumpState("flush 2"); } +void LocklessCommandFifo::wait() +{ + while(isEmpty() && !mInShutdown) { + mSignalToControl.set(); + mSignalToWorker.wait(); + } +} + const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData) { while(1) { //dumpState("get"); - while(isEmpty() && !mInShutdown) { - mSignalToControl.set(); - mSignalToWorker.wait(); - } - + wait(); if (mInShutdown) { *command = 0; *bytesData = 0; @@ -165,106 +175,55 @@ void LocklessCommandFifo::next() //dumpState("next"); } -void LocklessCommandFifo::makeSpace(uint32_t bytes) +bool LocklessCommandFifo::makeSpaceNonBlocking(uint32_t bytes) { - //dumpState("make space"); + //dumpState("make space non-blocking"); if ((mPut+bytes) > mEnd) { // Need to loop regardless of where get is. - while((mGet > mPut) && (mBuffer+4 >= mGet)) { - usleep(100); + if((mGet > mPut) && (mBuffer+4 >= mGet)) { + return false; } // Toss in a reset then the normal wait for space will do the rest. reinterpret_cast<uint16_t *>(mPut)[0] = 0; reinterpret_cast<uint16_t *>(mPut)[1] = 0; mPut = mBuffer; + mSignalToWorker.set(); } // it will fit here so we just need to wait for space. - while(getFreeSpace() < bytes) { - usleep(100); - } - -} - -void LocklessCommandFifo::dumpState(const char *s) const -{ - LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd); -} - -LocklessCommandFifo::Signal::Signal() -{ - mSet = true; -} - -LocklessCommandFifo::Signal::~Signal() -{ - pthread_mutex_destroy(&mMutex); - pthread_cond_destroy(&mCondition); -} - -bool LocklessCommandFifo::Signal::init() -{ - int status = pthread_mutex_init(&mMutex, NULL); - if (status) { - LOGE("LocklessFifo mutex init failure"); - return false; - } - - status = pthread_cond_init(&mCondition, NULL); - if (status) { - LOGE("LocklessFifo condition init failure"); - pthread_mutex_destroy(&mMutex); + if(getFreeSpace() < bytes) { return false; } return true; } -void LocklessCommandFifo::Signal::set() +void LocklessCommandFifo::makeSpace(uint32_t bytes) { - int status; + //dumpState("make space"); + if ((mPut+bytes) > mEnd) { + // Need to loop regardless of where get is. + while((mGet > mPut) && (mBuffer+4 >= mGet)) { + usleep(100); + } - status = pthread_mutex_lock(&mMutex); - if (status) { - LOGE("LocklessCommandFifo: error %i locking for set condition.", status); - return; + // Toss in a reset then the normal wait for space will do the rest. + reinterpret_cast<uint16_t *>(mPut)[0] = 0; + reinterpret_cast<uint16_t *>(mPut)[1] = 0; + mPut = mBuffer; + mSignalToWorker.set(); } - mSet = true; - - status = pthread_cond_signal(&mCondition); - if (status) { - LOGE("LocklessCommandFifo: error %i on set condition.", status); + // it will fit here so we just need to wait for space. + while(getFreeSpace() < bytes) { + usleep(100); } - status = pthread_mutex_unlock(&mMutex); - if (status) { - LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status); - } } -void LocklessCommandFifo::Signal::wait() +void LocklessCommandFifo::dumpState(const char *s) const { - int status; - - status = pthread_mutex_lock(&mMutex); - if (status) { - LOGE("LocklessCommandFifo: error %i locking for condition.", status); - return; - } - - if (!mSet) { - status = pthread_cond_wait(&mCondition, &mMutex); - if (status) { - LOGE("LocklessCommandFifo: error %i waiting on condition.", status); - } - } - mSet = false; - - status = pthread_mutex_unlock(&mMutex); - if (status) { - LOGE("LocklessCommandFifo: error %i unlocking for condition.", status); - } + LOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd); } diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h index d0a4356..b8ceeed 100644 --- a/libs/rs/rsLocklessFifo.h +++ b/libs/rs/rsLocklessFifo.h @@ -19,8 +19,10 @@ #include "rsUtils.h" +#include "rsSignal.h" namespace android { +namespace renderscript { // A simple FIFO to be used as a producer / consumer between two @@ -37,24 +39,7 @@ public: LocklessCommandFifo(); ~LocklessCommandFifo(); - protected: - class Signal { - public: - Signal(); - ~Signal(); - - bool init(); - - void set(); - void wait(); - - protected: - bool mSet; - pthread_mutex_t mMutex; - pthread_cond_t mCondition; - }; - uint8_t * volatile mPut; uint8_t * volatile mGet; uint8_t * mBuffer; @@ -65,18 +50,19 @@ protected: Signal mSignalToWorker; Signal mSignalToControl; - - public: void * reserve(uint32_t bytes); void commit(uint32_t command, uint32_t bytes); void commitSync(uint32_t command, uint32_t bytes); void flush(); + void wait(); + const void * get(uint32_t *command, uint32_t *bytesData); void next(); void makeSpace(uint32_t bytes); + bool makeSpaceNonBlocking(uint32_t bytes); bool isEmpty() const; uint32_t getFreeSpace() const; @@ -88,4 +74,5 @@ private: } +} #endif diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp index 2f21405..94eef13 100644 --- a/libs/rs/rsMatrix.cpp +++ b/libs/rs/rsMatrix.cpp @@ -73,7 +73,7 @@ void Matrix::loadRotate(float rot, float x, float y, float z) s = sinf(rot); const float len = sqrtf(x*x + y*y + z*z); - if (!(len != 1)) { + if (len != 1) { const float recipLen = 1.f / len; x *= recipLen; y *= recipLen; diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp index d595b4e..8e43f24 100644 --- a/libs/rs/rsMesh.cpp +++ b/libs/rs/rsMesh.cpp @@ -14,29 +14,257 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -using namespace android; -using namespace android::renderscript; - #include <GLES/gl.h> +#include <GLES2/gl2.h> #include <GLES/glext.h> +#else +#include "rsContextHostStub.h" + +#include <OpenGL/gl.h> +#include <OpenGl/glext.h> +#endif + + +using namespace android; +using namespace android::renderscript; Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { mAllocFile = __FILE__; mAllocLine = __LINE__; - mVerticies = NULL; - mVerticiesCount = 0; mPrimitives = NULL; mPrimitivesCount = 0; + mVertexBuffers = NULL; + mVertexBufferCount = 0; } Mesh::~Mesh() { + if(mVertexBuffers) { + delete[] mVertexBuffers; + } + + if(mPrimitives) { + for(uint32_t i = 0; i < mPrimitivesCount; i ++) { + delete mPrimitives[i]; + } + delete[] mPrimitives; + } +} + +void Mesh::render(Context *rsc) const +{ + for(uint32_t ct = 0; ct < mPrimitivesCount; ct ++) { + renderPrimitive(rsc, ct); + } +} + +void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const { + if (primIndex >= mPrimitivesCount) { + LOGE("Invalid primitive index"); + return; + } + + Primitive_t *prim = mPrimitives[primIndex]; + + if (prim->mIndexBuffer.get()) { + renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX()); + return; + } + + renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX()); +} + +void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const +{ + if (len < 1 || primIndex >= mPrimitivesCount) { + return; + } + + rsc->checkError("Mesh::renderPrimitiveRange 1"); + VertexArray va; + for (uint32_t ct=0; ct < mVertexBufferCount; ct++) { + mVertexBuffers[ct]->uploadCheck(rsc); + if (mVertexBuffers[ct]->getIsBufferObject()) { + va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID()); + } else { + va.setActiveBuffer(mVertexBuffers[ct]->getPtr()); + } + mVertexBuffers[ct]->getType()->enableGLVertexBuffer(&va); + } + 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"); } +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); + } + } +} + +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; + } + } +} + +void Mesh::serialize(OStream *stream) const +{ + // Need to identify ourselves + stream->addU32((uint32_t)getClassId()); + + String8 name(getName()); + 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(mPrimitivesCount); + // Store the primitives + for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) { + Primitive_t * prim = mPrimitives[pCount]; + + stream->addU8((uint8_t)prim->mPrimitive); + + if(prim->mIndexBuffer.get()) { + stream->addU32(1); + prim->mIndexBuffer->serialize(stream); + } + else { + stream->addU32(0); + } + } +} + +Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) +{ + // First make sure we are reading the correct object + RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); + if(classID != RS_A3D_CLASS_ID_MESH) { + LOGE("mesh loading skipped due to invalid class id"); + 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]; + + for(uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) { + Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); + mesh->mVertexBuffers[vCount].set(vertexAlloc); + } + } + + mesh->mPrimitivesCount = stream->loadU32(); + if(mesh->mPrimitivesCount) { + mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount]; + + // 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(); + + // 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); + } + } + } + + mesh->updateGLPrimitives(); + mesh->uploadAll(rsc); + + return mesh; +} + +void Mesh::computeBBox() { + float *posPtr = NULL; + uint32_t vectorSize = 0; + 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(); + const Element *bufferElem = bufferType->getElement(); + + for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) { + if(strcmp(bufferElem->getFieldName(ct), "position") == 0) { + 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); + numVerts = bufferType->getDimX(); + break; + } + } + if(posPtr) { + break; + } + } + + mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 1e6; + mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = -1e6; + if(!posPtr) { + LOGE("Unable to compute bounding box"); + mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 0.0f; + mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = 0.0f; + return; + } + + for(uint32_t i = 0; i < numVerts; i ++) { + for(uint32_t v = 0; v < vectorSize; v ++) { + mBBoxMin[v] = rsMin(mBBoxMin[v], posPtr[v]); + mBBoxMax[v] = rsMax(mBBoxMax[v], posPtr[v]); + } + posPtr += stride; + } +} + MeshContext::MeshContext() { @@ -46,3 +274,83 @@ MeshContext::~MeshContext() { } +namespace android { +namespace renderscript { + +RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) +{ + Mesh *sm = new Mesh(rsc); + 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; + } + + 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); + + sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va); + sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType; + sm->updateGLPrimitives(); +} + +void rsi_MeshGetVertexBufferCount(Context *rsc, RsMesh mv, int32_t *numVtx) +{ + Mesh *sm = static_cast<Mesh *>(mv); + *numVtx = sm->mVertexBufferCount; +} + +void rsi_MeshGetIndexCount(Context *rsc, RsMesh mv, int32_t *numIdx) +{ + Mesh *sm = static_cast<Mesh *>(mv); + *numIdx = sm->mPrimitivesCount; +} + +void rsi_MeshGetVertices(Context *rsc, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) +{ + Mesh *sm = static_cast<Mesh *>(mv); + rsAssert(vtxDataCount == sm->mVertexBufferCount); + + for(uint32_t ct = 0; ct < vtxDataCount; ct ++) { + vtxData[ct] = sm->mVertexBuffers[ct].get(); + sm->mVertexBuffers[ct]->incUserRef(); + } +} + +void rsi_MeshGetIndices(Context *rsc, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) +{ + Mesh *sm = static_cast<Mesh *>(mv); + rsAssert(idxDataCount == sm->mPrimitivesCount); + + 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(); + } + } + +} + + + + +}} diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h index 5201abd..ed01c38 100644 --- a/libs/rs/rsMesh.h +++ b/libs/rs/rsMesh.h @@ -32,45 +32,40 @@ public: Mesh(Context *); ~Mesh(); - struct Verticies_t - { - Allocation ** mAllocations; - uint32_t mAllocationCount; - - size_t mVertexDataSize; - - size_t mOffsetCoord; - size_t mOffsetTex; - size_t mOffsetNorm; - - size_t mSizeCoord; - size_t mSizeTex; - size_t mSizeNorm; - - uint32_t mBufferObject; - }; - + // 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 { - RsPrimitive mType; - Verticies_t *mVerticies; - - uint32_t mIndexCount; - uint16_t *mIndicies; + ObjectBaseRef<Allocation> mIndexBuffer; - uint32_t mRestartCounts; - uint16_t *mRestarts; + RsPrimitive mPrimitive; + uint32_t mGLPrimitive; }; - Verticies_t * mVerticies; - uint32_t mVerticiesCount; - Primitive_t ** mPrimitives; uint32_t mPrimitivesCount; + 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(); + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } + static Mesh *createFromStream(Context *rsc, IStream *stream); + + // Bounding volumes + float mBBoxMin[3]; + float mBBoxMax[3]; + void computeBBox(); - void analyzeElement(); protected: }; @@ -88,3 +83,4 @@ public: #endif //ANDROID_RS_TRIANGLE_MESH_H + diff --git a/libs/rs/rsMutex.cpp b/libs/rs/rsMutex.cpp new file mode 100644 index 0000000..37752f2 --- /dev/null +++ b/libs/rs/rsMutex.cpp @@ -0,0 +1,64 @@ +/* + * 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 "rsMutex.h" + +using namespace android; +using namespace android::renderscript; + + +Mutex::Mutex() +{ +} + +Mutex::~Mutex() +{ + pthread_mutex_destroy(&mMutex); +} + +bool Mutex::init() +{ + int status = pthread_mutex_init(&mMutex, NULL); + if (status) { + LOGE("Mutex::Mutex init failure"); + return false; + } + return true; +} + +bool Mutex::lock() +{ + int status; + status = pthread_mutex_lock(&mMutex); + if (status) { + LOGE("Mutex: error %i locking.", status); + return false; + } + return true; +} + +bool Mutex::unlock() +{ + int status; + status = pthread_mutex_unlock(&mMutex); + if (status) { + LOGE("Mutex error %i unlocking.", status); + return false; + } + return true; +} + + diff --git a/libs/rs/rsNoise.h b/libs/rs/rsMutex.h index 9040751..47725d7 100644 --- a/libs/rs/rsNoise.h +++ b/libs/rs/rsMutex.h @@ -14,22 +14,30 @@ * limitations under the License. */ -#ifndef ANDROID_RS_NOISE_H -#define ANDROID_RS_NOISE_H +#ifndef ANDROID_RS_MUTEX_H +#define ANDROID_RS_MUTEX_H + + +#include "rsUtils.h" -// --------------------------------------------------------------------------- namespace android { namespace renderscript { -void SC_normalizef2(float v[]); -void SC_normalizef3(float v[]); -float SC_noisef(float x); -float SC_noisef2(float x, float y); -float SC_noisef3(float x, float y, float z); -float SC_turbulencef2(float x, float y, float octaves); -float SC_turbulencef3(float x, float y, float z, float octaves); +class Mutex { +public: + Mutex(); + ~Mutex(); + + bool init(); + bool lock(); + bool unlock(); + +protected: + pthread_mutex_t mMutex; +}; } } #endif + diff --git a/libs/rs/rsNoise.cpp b/libs/rs/rsNoise.cpp deleted file mode 100644 index 4b67586..0000000 --- a/libs/rs/rsNoise.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * This implementation of the noise functions was ported from the Java - * implementation by Jerry Huxtable (http://www.jhlabs.com) under - * Apache License 2.0 (see http://jhlabs.com/ip/filters/download.html) - * - * Original header: - * - * Copyright 2006 Jerry Huxtable - * - * 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 "rsNoise.h" - -#include <math.h> -#include <stdlib.h> -#include <time.h> - -namespace android { -namespace renderscript { - -#define B 0x100 -#define BM 0xff -#define N 0x1000 - -static int p[B + B + 2]; -static float g3[B + B + 2][3]; -static float g2[B + B + 2][2]; -static float g1[B + B + 2]; -static bool noise_start = true; - -#define lerpf(start, stop, amount) start + (stop - start) * amount - -static inline float noise_sCurve(float t) -{ - return t * t * (3.0f - 2.0f * t); -} - -inline void SC_normalizef2(float v[]) -{ - float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1]); - v[0] = v[0] / s; - v[1] = v[1] / s; -} - -inline void SC_normalizef3(float v[]) -{ - float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - v[0] = v[0] / s; - v[1] = v[1] / s; - v[2] = v[2] / s; -} - -static void noise_init() -{ - int i, j, k; - - for (i = 0; i < B; i++) { - p[i] = i; - - g1[i] = (float)((rand() % (B + B)) - B) / B; - - for (j = 0; j < 2; j++) - g2[i][j] = (float)((rand() % (B + B)) - B) / B; - SC_normalizef2(g2[i]); - - for (j = 0; j < 3; j++) - g3[i][j] = (float)((rand() % (B + B)) - B) / B; - SC_normalizef3(g3[i]); - } - - for (i = B-1; i >= 0; i--) { - k = p[i]; - p[i] = p[j = rand() % B]; - p[j] = k; - } - - for (i = 0; i < B + 2; i++) { - p[B + i] = p[i]; - g1[B + i] = g1[i]; - for (j = 0; j < 2; j++) - g2[B + i][j] = g2[i][j]; - for (j = 0; j < 3; j++) - g3[B + i][j] = g3[i][j]; - } -} - -float SC_noisef(float x) -{ - srand(time(NULL)); - int bx0, bx1; - float rx0, rx1, sx, t, u, v; - - if (noise_start) { - noise_start = false; - noise_init(); - } - - t = x + N; - bx0 = ((int)t) & BM; - bx1 = (bx0+1) & BM; - rx0 = t - (int)t; - rx1 = rx0 - 1.0f; - - sx = noise_sCurve(rx0); - - u = rx0 * g1[p[bx0]]; - v = rx1 * g1[p[bx1]]; - return 2.3f * lerpf(u, v, sx); -} - -float SC_noisef2(float x, float y) -{ - srand(time(NULL)); - int bx0, bx1, by0, by1, b00, b10, b01, b11; - float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v; - float *q; - int i, j; - - if (noise_start) { - noise_start = false; - noise_init(); - } - - t = x + N; - bx0 = ((int)t) & BM; - bx1 = (bx0+1) & BM; - rx0 = t - (int)t; - rx1 = rx0 - 1.0f; - - t = y + N; - by0 = ((int)t) & BM; - by1 = (by0+1) & BM; - ry0 = t - (int)t; - ry1 = ry0 - 1.0f; - - i = p[bx0]; - j = p[bx1]; - - b00 = p[i + by0]; - b10 = p[j + by0]; - b01 = p[i + by1]; - b11 = p[j + by1]; - - sx = noise_sCurve(rx0); - sy = noise_sCurve(ry0); - - q = g2[b00]; u = rx0 * q[0] + ry0 * q[1]; - q = g2[b10]; v = rx1 * q[0] + ry0 * q[1]; - a = lerpf(u, v, sx); - - q = g2[b01]; u = rx0 * q[0] + ry1 * q[1]; - q = g2[b11]; v = rx1 * q[0] + ry1 * q[1]; - b = lerpf(u, v, sx); - - return 1.5f*lerpf(a, b, sy); -} - -float SC_noisef3(float x, float y, float z) -{ - srand(time(NULL)); - int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; - float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v; - float *q; - int i, j; - - if (noise_start) { - noise_start = false; - noise_init(); - } - - t = x + N; - bx0 = ((int)t) & BM; - bx1 = (bx0+1) & BM; - rx0 = t - (int)t; - rx1 = rx0 - 1.0f; - - t = y + N; - by0 = ((int)t) & BM; - by1 = (by0+1) & BM; - ry0 = t - (int)t; - ry1 = ry0 - 1.0f; - - t = z + N; - bz0 = ((int)t) & BM; - bz1 = (bz0+1) & BM; - rz0 = t - (int)t; - rz1 = rz0 - 1.0f; - - i = p[bx0]; - j = p[bx1]; - - b00 = p[i + by0]; - b10 = p[j + by0]; - b01 = p[i + by1]; - b11 = p[j + by1]; - - t = noise_sCurve(rx0); - sy = noise_sCurve(ry0); - sz = noise_sCurve(rz0); - - q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2]; - q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2]; - a = lerpf(u, v, t); - - q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2]; - q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2]; - b = lerpf(u, v, t); - - c = lerpf(a, b, sy); - - q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2]; - q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2]; - a = lerpf(u, v, t); - - q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2]; - q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2]; - b = lerpf(u, v, t); - - d = lerpf(a, b, sy); - - return 1.5f*lerpf(c, d, sz); -} - -float SC_turbulencef2(float x, float y, float octaves) -{ - srand(time(NULL)); - float t = 0.0f; - - for (float f = 1.0f; f <= octaves; f *= 2) - t += fabs(SC_noisef2(f * x, f * y)) / f; - return t; -} - -float SC_turbulencef3(float x, float y, float z, float octaves) -{ - srand(time(NULL)); - float t = 0.0f; - - for (float f = 1.0f; f <= octaves; f *= 2) - t += fabs(SC_noisef3(f * x, f * y, f * z)) / f; - return t; -} - -} -} diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp index 677413e..e4b07c4 100644 --- a/libs/rs/rsObjectBase.cpp +++ b/libs/rs/rsObjectBase.cpp @@ -15,22 +15,30 @@ */ #include "rsObjectBase.h" + +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif using namespace android; using namespace android::renderscript; +pthread_mutex_t ObjectBase::gObjectInitMutex = PTHREAD_MUTEX_INITIALIZER; + ObjectBase::ObjectBase(Context *rsc) { mUserRefCount = 0; mSysRefCount = 0; - mName = NULL; - mRSC = NULL; + mRSC = rsc; mNext = NULL; mPrev = NULL; mAllocFile = __FILE__; mAllocLine = __LINE__; - setContext(rsc); + + rsAssert(rsc); + add(); } ObjectBase::~ObjectBase() @@ -39,50 +47,55 @@ ObjectBase::~ObjectBase() rsAssert(!mUserRefCount); rsAssert(!mSysRefCount); remove(); - delete[] mName; } void ObjectBase::dumpLOGV(const char *op) const { - if (mName) { + if (mName.size()) { LOGV("%s RSobj %p, name %s, refs %i,%i from %s,%i links %p,%p,%p", - op, this, mName, mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC); + op, this, mName.string(), mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC); } else { LOGV("%s RSobj %p, no-name, refs %i,%i from %s,%i links %p,%p,%p", op, this, mUserRefCount, mSysRefCount, mAllocFile, mAllocLine, mNext, mPrev, mRSC); } } -void ObjectBase::setContext(Context *rsc) +void ObjectBase::incUserRef() const { - if (mRSC) { - remove(); - } - mRSC = rsc; - if (rsc) { - add(); - } + lockUserRef(); + mUserRefCount++; + unlockUserRef(); + //LOGV("ObjectBase %p inc ref %i", this, mUserRefCount); } -void ObjectBase::incUserRef() const +void ObjectBase::prelockedIncUserRef() const { - mUserRefCount ++; - //LOGV("ObjectBase %p inc ref %i", this, mRefCount); + mUserRefCount++; } void ObjectBase::incSysRef() const { mSysRefCount ++; - //LOGV("ObjectBase %p inc ref %i", this, mRefCount); + //LOGV("ObjectBase %p inc ref %i", this, mSysRefCount); } bool ObjectBase::checkDelete() const { if (!(mSysRefCount | mUserRefCount)) { + lockUserRef(); + + // Recheck the user ref count since it can be incremented from other threads. + if (mUserRefCount) { + unlockUserRef(); + return false; + } + if (mRSC && mRSC->props.mLogObjects) { dumpLOGV("checkDelete"); } delete this; + + unlockUserRef(); return true; } return false; @@ -90,45 +103,59 @@ bool ObjectBase::checkDelete() const bool ObjectBase::decUserRef() const { + lockUserRef(); rsAssert(mUserRefCount > 0); - mUserRefCount --; - //dumpObj("decUserRef"); - return checkDelete(); + //dumpLOGV("decUserRef"); + mUserRefCount--; + unlockUserRef(); + bool ret = checkDelete(); + return ret; } bool ObjectBase::zeroUserRef() const { + lockUserRef(); + // This can only happen during cleanup and is therefore + // thread safe. mUserRefCount = 0; - //dumpObj("zeroUserRef"); - return checkDelete(); + //dumpLOGV("zeroUserRef"); + unlockUserRef(); + bool ret = checkDelete(); + return ret; } bool ObjectBase::decSysRef() const { rsAssert(mSysRefCount > 0); mSysRefCount --; - //dumpObj("decSysRef"); + //dumpLOGV("decSysRef"); return checkDelete(); } void ObjectBase::setName(const char *name) { - setName(name, strlen(name)); + mName.setTo(name); } void ObjectBase::setName(const char *name, uint32_t len) { - delete mName; - mName = NULL; - if (name) { - mName = new char[len + 1]; - memcpy(mName, name, len); - mName[len] = 0; - } + mName.setTo(name, len); +} + +void ObjectBase::lockUserRef() +{ + pthread_mutex_lock(&gObjectInitMutex); +} + +void ObjectBase::unlockUserRef() +{ + pthread_mutex_unlock(&gObjectInitMutex); } void ObjectBase::add() const { + pthread_mutex_lock(&gObjectInitMutex); + rsAssert(!mNext); rsAssert(!mPrev); //LOGV("calling add rsc %p", mRSC); @@ -137,16 +164,22 @@ void ObjectBase::add() const mRSC->mObjHead->mPrev = this; } mRSC->mObjHead = this; + + pthread_mutex_unlock(&gObjectInitMutex); } void ObjectBase::remove() const { + // Should be within gObjectInitMutex lock + // lock will be from checkDelete a few levels up in the stack. + //LOGV("calling remove rsc %p", mRSC); if (!mRSC) { rsAssert(!mPrev); rsAssert(!mNext); return; } + if (mRSC->mObjHead == this) { mRSC->mObjHead = mNext; } @@ -162,6 +195,8 @@ void ObjectBase::remove() const void ObjectBase::zeroAllUserRef(Context *rsc) { + lockUserRef(); + if (rsc->props.mLogObjects) { LOGV("Forcing release of all outstanding user refs."); } @@ -184,10 +219,14 @@ void ObjectBase::zeroAllUserRef(Context *rsc) LOGV("Objects remaining."); dumpAll(rsc); } + + unlockUserRef(); } void ObjectBase::dumpAll(Context *rsc) { + lockUserRef(); + LOGV("Dumping all objects"); const ObjectBase * o = rsc->mObjHead; while (o) { @@ -195,5 +234,23 @@ void ObjectBase::dumpAll(Context *rsc) o->dumpLOGV(" "); o = o->mNext; } + + unlockUserRef(); +} + +bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) +{ + lockUserRef(); + + const ObjectBase * o = rsc->mObjHead; + while (o) { + if (o == obj) { + unlockUserRef(); + return true; + } + o = o->mNext; + } + unlockUserRef(); + return false; } diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h index bb03b87..8d1ace1 100644 --- a/libs/rs/rsObjectBase.h +++ b/libs/rs/rsObjectBase.h @@ -24,6 +24,7 @@ namespace android { namespace renderscript { class Context; +class OStream; // An element is a group of Components that occupies one cell in a structure. class ObjectBase @@ -38,20 +39,27 @@ public: void incUserRef() const; bool decUserRef() const; bool zeroUserRef() const; + void prelockedIncUserRef() const; const char * getName() const { - return mName; + return mName.string(); } void setName(const char *); void setName(const char *, uint32_t len); Context * getContext() const {return mRSC;} - void setContext(Context *); static void zeroAllUserRef(Context *rsc); static void dumpAll(Context *rsc); virtual void dumpLOGV(const char *prefix) const; + virtual void serialize(OStream *stream) const = 0; + virtual RsA3DClassID getClassId() const = 0; + + static bool isValid(const Context *rsc, const ObjectBase *obj); + + static void lockUserRef(); + static void unlockUserRef(); protected: const char *mAllocFile; @@ -59,12 +67,14 @@ protected: Context *mRSC; private: + static pthread_mutex_t gObjectInitMutex; + void add() const; void remove() const; bool checkDelete() const; - char * mName; + String8 mName; mutable int32_t mSysRefCount; mutable int32_t mUserRefCount; diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 70e2868..10e00e6 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -14,16 +14,21 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include "rsProgram.h" - #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsProgram.h" using namespace android; using namespace android::renderscript; - Program::Program(Context *rsc) : ObjectBase(rsc) { mAllocFile = __FILE__; @@ -32,7 +37,10 @@ Program::Program(Context *rsc) : ObjectBase(rsc) mShaderID = 0; mAttribCount = 0; mUniformCount = 0; + mTextureCount = 0; + mTextures = NULL; + mSamplers = NULL; mInputElements = NULL; mOutputElements = NULL; mConstantTypes = NULL; @@ -40,6 +48,7 @@ Program::Program(Context *rsc) : ObjectBase(rsc) mOutputCount = 0; mConstantCount = 0; mIsValid = false; + mIsInternal = false; } Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, @@ -73,6 +82,8 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, } } + mTextures = new ObjectBaseRef<Allocation>[mTextureCount]; + mSamplers = new ObjectBaseRef<Sampler>[mTextureCount]; mInputElements = new ObjectBaseRef<Element>[mInputCount]; mOutputElements = new ObjectBaseRef<Element>[mOutputCount]; mConstantTypes = new ObjectBaseRef<Type>[mConstantCount]; @@ -91,15 +102,37 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1])); } } + mIsInternal = false; + uint32_t internalTokenLen = strlen(RS_SHADER_INTERNAL); + if(shaderLength > internalTokenLen && + strncmp(RS_SHADER_INTERNAL, shaderText, internalTokenLen) == 0) { + mIsInternal = true; + shaderText += internalTokenLen; + shaderLength -= internalTokenLen; + } mUserShader.setTo(shaderText, shaderLength); } Program::~Program() { + if(mRSC->props.mLogShaders) { + LOGV("Program::~Program with shader id %u", mShaderID); + } + + if(mShaderID) { + glDeleteShader(mShaderID); + } + for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) { - bindAllocation(NULL, ct); + bindAllocation(NULL, NULL, ct); } + for (uint32_t ct=0; ct < mTextureCount; ct++) { + bindTexture(NULL, ct, NULL); + bindSampler(NULL, ct, NULL); + } + delete[] mTextures; + delete[] mSamplers; delete[] mInputElements; delete[] mOutputElements; delete[] mConstantTypes; @@ -109,8 +142,22 @@ Program::~Program() } -void Program::bindAllocation(Allocation *alloc, uint32_t slot) +void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { + if (alloc != NULL) { + if (slot >= mConstantCount) { + LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u", + slot, (uint32_t)this, mConstantCount); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation"); + return; + } + if (!alloc->getType()->isEqual(mConstantTypes[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) { return; } @@ -124,10 +171,11 @@ void Program::bindAllocation(Allocation *alloc, uint32_t slot) mDirty = true; } -void Program::bindTexture(uint32_t slot, Allocation *a) +void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) { - if (slot >= MAX_TEXTURE) { - LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE"); + if (slot >= mTextureCount) { + LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture"); return; } @@ -136,10 +184,11 @@ void Program::bindTexture(uint32_t slot, Allocation *a) mDirty = true; } -void Program::bindSampler(uint32_t slot, Sampler *s) +void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) { - if (slot >= MAX_TEXTURE) { - LOGE("Attempt to bind a Sampler to a slot > MAX_TEXTURE"); + if (slot >= mTextureCount) { + LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler"); return; } @@ -235,7 +284,159 @@ 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); + mShader.append(";\n"); + } + } +} + +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; + if(!isFragment) { + slot = sc->vtxUniformSlot(uidx); + } + else { + slot = sc->fragUniformSlot(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); + } + if (slot >= 0) { + if(f->getType() == RS_TYPE_MATRIX_4X4) { + if(rsc->props.mLogShadersUniforms) { + 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]); + } + glUniformMatrix4fv(slot, 1, GL_FALSE, fd); + } + else if(f->getType() == RS_TYPE_MATRIX_3X3) { + if(rsc->props.mLogShadersUniforms) { + 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]); + } + glUniformMatrix3fv(slot, 1, GL_FALSE, fd); + } + else if(f->getType() == RS_TYPE_MATRIX_2X2) { + if(rsc->props.mLogShadersUniforms){ + LOGV("Matrix2x2"); + LOGV("{%f, %f", fd[0], fd[2]); + LOGV(" %f, %f}", fd[1], fd[3]); + } + glUniformMatrix2fv(slot, 1, GL_FALSE, fd); + } + else { + switch(f->getComponent().getVectorSize()) { + case 1: + if(rsc->props.mLogShadersUniforms) { + LOGV("Uniform 1 = %f", fd[0]); + } + glUniform1fv(slot, 1, fd); + break; + case 2: + if(rsc->props.mLogShadersUniforms) { + LOGV("Uniform 2 = %f %f", fd[0], fd[1]); + } + glUniform2fv(slot, 1, fd); + break; + case 3: + if(rsc->props.mLogShadersUniforms) { + LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); + } + glUniform3fv(slot, 1, fd); + break; + case 4: + if(rsc->props.mLogShadersUniforms) { + LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); + } + glUniform4fv(slot, 1, fd); + break; + default: + rsAssert(0); + } + } + } + uidx ++; + } + } +} +void Program::initAddUserElement(const Element *e, String8 *names, 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, count, prefix); + } + else if(e->getFieldName(ct)[0] != '#') { + String8 tmp(prefix); + tmp.append(e->getFieldName(ct)); + names[*count].setTo(tmp.string()); + (*count)++; + } + } +} namespace android { namespace renderscript { @@ -244,19 +445,19 @@ namespace renderscript { void rsi_ProgramBindConstants(Context *rsc, RsProgram vp, uint32_t slot, RsAllocation constants) { Program *p = static_cast<Program *>(vp); - p->bindAllocation(static_cast<Allocation *>(constants), slot); + p->bindAllocation(rsc, static_cast<Allocation *>(constants), slot); } void rsi_ProgramBindTexture(Context *rsc, RsProgram vpf, uint32_t slot, RsAllocation a) { Program *p = static_cast<Program *>(vpf); - p->bindTexture(slot, static_cast<Allocation *>(a)); + p->bindTexture(rsc, slot, static_cast<Allocation *>(a)); } void rsi_ProgramBindSampler(Context *rsc, RsProgram vpf, uint32_t slot, RsSampler s) { Program *p = static_cast<Program *>(vpf); - p->bindSampler(slot, static_cast<Sampler *>(s)); + p->bindSampler(rsc, slot, static_cast<Sampler *>(s)); } } diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index 86f85fb..c93033b 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -23,29 +23,30 @@ // --------------------------------------------------------------------------- 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 { public: const static uint32_t MAX_ATTRIBS = 8; const static uint32_t MAX_UNIFORMS = 16; - const static uint32_t MAX_TEXTURE = 2; Program(Context *); Program(Context *, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength); virtual ~Program(); - void bindAllocation(Allocation *, uint32_t slot); + void bindAllocation(Context *, Allocation *, uint32_t slot); virtual void createShader(); - bool isUserProgram() const {return mUserShader.size() > 0;} + bool isUserProgram() const {return !mIsInternal;} - void bindTexture(uint32_t slot, Allocation *); - void bindSampler(uint32_t slot, Sampler *); + 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); @@ -71,6 +72,12 @@ protected: 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 *count, const char *prefix); ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS]; @@ -91,8 +98,8 @@ protected: // and filtered. // // Constants are strictly accessed by programetic loads. - ObjectBaseRef<Allocation> mTextures[MAX_TEXTURE]; - ObjectBaseRef<Sampler> mSamplers[MAX_TEXTURE]; + ObjectBaseRef<Allocation> *mTextures; + ObjectBaseRef<Sampler> *mSamplers; bool loadShader(Context *, uint32_t type); diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index c17b94c..81b4fa4 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -14,42 +14,23 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include "rsProgramFragment.h" - #include <GLES/gl.h> #include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsProgramFragment.h" using namespace android; using namespace android::renderscript; - -ProgramFragment::ProgramFragment(Context *rsc, const uint32_t * params, - uint32_t paramLength) : - Program(rsc) -{ - mAllocFile = __FILE__; - mAllocLine = __LINE__; - rsAssert(paramLength = 5); - - mEnvModes[0] = (RsTexEnvMode)params[0]; - mTextureFormats[0] = params[1]; - mEnvModes[1] = (RsTexEnvMode)params[2]; - mTextureFormats[1] = params[3]; - mPointSpriteEnable = params[4] != 0; - - mTextureEnableMask = 0; - if (mEnvModes[0]) { - mTextureEnableMask |= 1; - } - if (mEnvModes[1]) { - mTextureEnableMask |= 2; - } - init(rsc); -} - ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : @@ -58,100 +39,68 @@ ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, mAllocFile = __FILE__; mAllocLine = __LINE__; + mConstantColor[0] = 1.f; + mConstantColor[1] = 1.f; + mConstantColor[2] = 1.f; + mConstantColor[3] = 1.f; + init(rsc); - mTextureEnableMask = (1 << mTextureCount) -1; } - ProgramFragment::~ProgramFragment() { + if(mShaderID) { + mRSC->mShaderCache.cleanupFragment(mShaderID); + } } -void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state) +void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) { - if ((state->mLast.get() == this) && !mDirty) { + if(isUserProgram()) { + LOGE("Attempting to set fixed function emulation color on user program"); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set fixed function emulation color on user program"); return; } - state->mLast.set(this); - - for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) { - glActiveTexture(GL_TEXTURE0 + ct); - if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) { - glDisable(GL_TEXTURE_2D); - continue; - } - - glEnable(GL_TEXTURE_2D); - if (rsc->checkVersion1_1()) { - if (mPointSpriteEnable) { - glEnable(GL_POINT_SPRITE_OES); - } else { - glDisable(GL_POINT_SPRITE_OES); - } - glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable); - } - mTextures[ct]->uploadCheck(rsc); - glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID()); - - switch(mEnvModes[ct]) { - case RS_TEX_ENV_MODE_NONE: - rsAssert(0); - break; - case RS_TEX_ENV_MODE_REPLACE: - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - break; - case RS_TEX_ENV_MODE_MODULATE: - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - break; - case RS_TEX_ENV_MODE_DECAL: - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - break; - } - - if (mSamplers[ct].get()) { - mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2()); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - // Gross hack. - if (ct == 2) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - } + if(mConstants[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; } - glActiveTexture(GL_TEXTURE0); - mDirty = false; - rsc->checkError("ProgramFragment::setupGL"); + mConstantColor[0] = r; + mConstantColor[1] = g; + mConstantColor[2] = b; + mConstantColor[3] = a; + memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float)); + mDirty = true; } -void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, ShaderCache *sc) +void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) { - //LOGE("sgl2 frag1 %x", glGetError()); if ((state->mLast.get() == this) && !mDirty) { - //return; + return; } state->mLast.set(this); rsc->checkError("ProgramFragment::setupGL2 start"); - for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) { + + 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 (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) { + if (!mTextures[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; } @@ -159,16 +108,16 @@ void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID()); rsc->checkError("ProgramFragment::setupGL2 tex bind"); if (mSamplers[ct].get()) { - mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2()); + mSamplers[ct]->setupGL(rsc, mTextures[ct].get()); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); rsc->checkError("ProgramFragment::setupGL2 tex env"); } - glUniform1i(sc->fragUniformSlot(ct), ct); + glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct); rsc->checkError("ProgramFragment::setupGL2 uniforms"); } @@ -183,110 +132,47 @@ void ProgramFragment::loadShader(Context *rsc) { void ProgramFragment::createShader() { - mShader.setTo("precision mediump float;\n"); - mShader.append("varying vec4 varColor;\n"); - mShader.append("varying vec4 varTex0;\n"); - if (mUserShader.length() > 1) { + mShader.append("precision mediump float;\n"); + appendUserConstants(); + char buf[256]; for (uint32_t ct=0; ct < mTextureCount; ct++) { - char buf[256]; - sprintf(buf, "uniform sampler2D uni_Tex%i;\n", ct); + sprintf(buf, "uniform sampler2D UNI_Tex%i;\n", ct); mShader.append(buf); } - mShader.append(mUserShader); } else { - uint32_t mask = mTextureEnableMask; - uint32_t texNum = 0; - while (mask) { - if (mask & 1) { - char buf[64]; - mShader.append("uniform sampler2D uni_Tex"); - sprintf(buf, "%i", texNum); - mShader.append(buf); - mShader.append(";\n"); - } - mask >>= 1; - texNum++; - } - - - mShader.append("void main() {\n"); - mShader.append(" vec4 col = varColor;\n"); + LOGE("ProgramFragment::createShader cannot create program, shader code not defined"); + rsAssert(0); + } +} - if (mTextureEnableMask) { - if (mPointSpriteEnable) { - mShader.append(" vec2 t0 = gl_PointCoord;\n"); - } else { - mShader.append(" vec2 t0 = varTex0.xy;\n"); - } +void ProgramFragment::init(Context *rsc) +{ + mUniformCount = 0; + if (mUserShader.size() > 0) { + for (uint32_t ct=0; ct < mConstantCount; ct++) { + initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, RS_SHADER_UNI); } + } + mTextureUniformIndexStart = mUniformCount; + char buf[256]; + for (uint32_t ct=0; ct < mTextureCount; ct++) { + sprintf(buf, "UNI_Tex%i", ct); + mUniformNames[mUniformCount++].setTo(buf); + } - mask = mTextureEnableMask; - texNum = 0; - while (mask) { - if (mask & 1) { - switch(mEnvModes[texNum]) { - case RS_TEX_ENV_MODE_NONE: - rsAssert(0); - break; - case RS_TEX_ENV_MODE_REPLACE: - switch(mTextureFormats[texNum]) { - case 1: - mShader.append(" col.a = texture2D(uni_Tex0, t0).a;\n"); - break; - case 2: - mShader.append(" col.rgba = texture2D(uni_Tex0, t0).rgba;\n"); - break; - case 3: - mShader.append(" col.rgb = texture2D(uni_Tex0, t0).rgb;\n"); - break; - case 4: - mShader.append(" col.rgba = texture2D(uni_Tex0, t0).rgba;\n"); - break; - } - break; - case RS_TEX_ENV_MODE_MODULATE: - switch(mTextureFormats[texNum]) { - case 1: - mShader.append(" col.a *= texture2D(uni_Tex0, t0).a;\n"); - break; - case 2: - mShader.append(" col.rgba *= texture2D(uni_Tex0, t0).rgba;\n"); - break; - case 3: - mShader.append(" col.rgb *= texture2D(uni_Tex0, t0).rgb;\n"); - break; - case 4: - mShader.append(" col.rgba *= texture2D(uni_Tex0, t0).rgba;\n"); - break; - } - break; - case RS_TEX_ENV_MODE_DECAL: - mShader.append(" col = texture2D(uni_Tex0, t0);\n"); - break; - } - - } - mask >>= 1; - texNum++; - } + createShader(); +} - //mShader.append(" col.a = 1.0;\n"); - //mShader.append(" col.r = 0.5;\n"); +void ProgramFragment::serialize(OStream *stream) const +{ - mShader.append(" gl_FragColor = col;\n"); - mShader.append("}\n"); - } } -void ProgramFragment::init(Context *rsc) +ProgramFragment *ProgramFragment::createFromStream(Context *rsc, IStream *stream) { - mUniformCount = 2; - mUniformNames[0].setTo("uni_Tex0"); - mUniformNames[1].setTo("uni_Tex1"); - - createShader(); + return NULL; } ProgramFragmentState::ProgramFragmentState() @@ -300,16 +186,39 @@ ProgramFragmentState::~ProgramFragmentState() } -void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h) +void ProgramFragmentState::init(Context *rsc) { - uint32_t tmp[5] = { - RS_TEX_ENV_MODE_NONE, 0, - RS_TEX_ENV_MODE_NONE, 0, - 0 - }; - ProgramFragment *pf = new ProgramFragment(rsc, tmp, 5); + String8 shaderString(RS_SHADER_INTERNAL); + shaderString.append("varying lowp vec4 varColor;\n"); + shaderString.append("varying vec2 varTex0;\n"); + shaderString.append("void main() {\n"); + shaderString.append(" lowp vec4 col = UNI_Color;\n"); + shaderString.append(" gl_FragColor = col;\n"); + shaderString.append("}\n"); + + const Element *colorElem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); + rsc->mStateElement.elementBuilderBegin(); + rsc->mStateElement.elementBuilderAdd(colorElem, "Color", 1); + const Element *constInput = rsc->mStateElement.elementBuilderCreate(rsc); + + Type *inputType = new Type(rsc); + inputType->setElement(constInput); + inputType->setDimX(1); + inputType->compute(); + + uint32_t tmp[4]; + tmp[0] = RS_PROGRAM_PARAM_CONSTANT; + tmp[1] = (uint32_t)inputType; + tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT; + tmp[3] = 0; + + Allocation *constAlloc = new Allocation(rsc, inputType); + ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), + shaderString.length(), tmp, 4); + pf->bindAllocation(rsc, constAlloc, 0); + pf->setConstantColor(rsc, 1.0f, 1.0f, 1.0f, 1.0f); + mDefault.set(pf); - pf->init(rsc); } void ProgramFragmentState::deinit(Context *rsc) @@ -322,21 +231,13 @@ void ProgramFragmentState::deinit(Context *rsc) namespace android { namespace renderscript { -RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, - const uint32_t * params, - uint32_t paramLength) -{ - ProgramFragment *pf = new ProgramFragment(rsc, params, paramLength); - pf->incUserRef(); - return pf; -} - -RsProgramFragment rsi_ProgramFragmentCreate2(Context *rsc, const char * shaderText, +RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) { ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength); pf->incUserRef(); + //LOGE("rsi_ProgramFragmentCreate %p", pf); return pf; } diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index 9fa565d..1cf9ca7 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -28,26 +28,25 @@ class ProgramFragmentState; class ProgramFragment : public Program { public: - ProgramFragment(Context *, const uint32_t * params, uint32_t paramLength); ProgramFragment(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength); virtual ~ProgramFragment(); - virtual void setupGL(const Context *, ProgramFragmentState *); - virtual void setupGL2(const Context *, ProgramFragmentState *, ShaderCache *sc); + virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc); 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); + + void setConstantColor(Context *, float, float, float, float); protected: - // Hacks to create a program for now - uint32_t mTextureFormats[MAX_TEXTURE]; - uint32_t mTextureDimensions[MAX_TEXTURE]; - RsTexEnvMode mEnvModes[MAX_TEXTURE]; - uint32_t mTextureEnableMask; - bool mPointSpriteEnable; + float mConstantColor[4]; + int32_t mTextureUniformIndexStart; }; class ProgramFragmentState @@ -57,10 +56,9 @@ public: ~ProgramFragmentState(); ProgramFragment *mPF; - void init(Context *rsc, int32_t w, int32_t h); + void init(Context *rsc); void deinit(Context *rsc); - ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE]; ObjectBaseRef<ProgramFragment> mDefault; Vector<ProgramFragment *> mPrograms; diff --git a/libs/rs/rsProgramRaster.cpp b/libs/rs/rsProgramRaster.cpp index 13887d1..62d060d 100644 --- a/libs/rs/rsProgramRaster.cpp +++ b/libs/rs/rsProgramRaster.cpp @@ -14,11 +14,17 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include "rsProgramRaster.h" - #include <GLES/gl.h> #include <GLES/glext.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGl/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsProgramRaster.h" using namespace android; using namespace android::renderscript; @@ -35,9 +41,8 @@ ProgramRaster::ProgramRaster(Context *rsc, mPointSmooth = pointSmooth; mLineSmooth = lineSmooth; mPointSprite = pointSprite; - - mPointSize = 1.0f; mLineWidth = 1.0f; + mCull = RS_CULL_BACK; } ProgramRaster::~ProgramRaster() @@ -47,53 +52,48 @@ ProgramRaster::~ProgramRaster() void ProgramRaster::setLineWidth(float s) { mLineWidth = s; + mDirty = true; } -void ProgramRaster::setPointSize(float s) +void ProgramRaster::setCullMode(RsCullMode mode) { - mPointSize = s; + mCull = mode; + mDirty = true; } -void ProgramRaster::setupGL(const Context *rsc, ProgramRasterState *state) +void ProgramRaster::setupGL2(const Context *rsc, ProgramRasterState *state) { - if (state->mLast.get() == this) { + if (state->mLast.get() == this && !mDirty) { return; } state->mLast.set(this); - - glPointSize(mPointSize); - if (mPointSmooth) { - glEnable(GL_POINT_SMOOTH); - } else { - glDisable(GL_POINT_SMOOTH); + 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; } +} - glLineWidth(mLineWidth); - if (mLineSmooth) { - glEnable(GL_LINE_SMOOTH); - } else { - glDisable(GL_LINE_SMOOTH); - } +void ProgramRaster::serialize(OStream *stream) const +{ - if (rsc->checkVersion1_1()) { - if (mPointSprite) { - glEnable(GL_POINT_SPRITE_OES); - } else { - glDisable(GL_POINT_SPRITE_OES); - } - } } -void ProgramRaster::setupGL2(const Context *rsc, ProgramRasterState *state) +ProgramRaster *ProgramRaster::createFromStream(Context *rsc, IStream *stream) { - if (state->mLast.get() == this) { - return; - } - state->mLast.set(this); + return NULL; } - - ProgramRasterState::ProgramRasterState() { } @@ -102,7 +102,7 @@ ProgramRasterState::~ProgramRasterState() { } -void ProgramRasterState::init(Context *rsc, int32_t w, int32_t h) +void ProgramRasterState::init(Context *rsc) { ProgramRaster *pr = new ProgramRaster(rsc, false, false, false); mDefault.set(pr); @@ -118,7 +118,7 @@ void ProgramRasterState::deinit(Context *rsc) namespace android { namespace renderscript { -RsProgramRaster rsi_ProgramRasterCreate(Context * rsc, RsElement in, RsElement out, +RsProgramRaster rsi_ProgramRasterCreate(Context * rsc, bool pointSmooth, bool lineSmooth, bool pointSprite) @@ -131,16 +131,16 @@ RsProgramRaster rsi_ProgramRasterCreate(Context * rsc, RsElement in, RsElement o return pr; } -void rsi_ProgramRasterSetPointSize(Context * rsc, RsProgramRaster vpr, float s) +void rsi_ProgramRasterSetLineWidth(Context * rsc, RsProgramRaster vpr, float s) { ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); - pr->setPointSize(s); + pr->setLineWidth(s); } -void rsi_ProgramRasterSetLineWidth(Context * rsc, RsProgramRaster vpr, float s) +void rsi_ProgramRasterSetCullMode(Context * rsc, RsProgramRaster vpr, RsCullMode mode) { ProgramRaster *pr = static_cast<ProgramRaster *>(vpr); - pr->setLineWidth(s); + pr->setCullMode(mode); } diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h index c3a9c90..d5ed686 100644 --- a/libs/rs/rsProgramRaster.h +++ b/libs/rs/rsProgramRaster.h @@ -34,21 +34,20 @@ public: bool pointSprite); virtual ~ProgramRaster(); - virtual void setupGL(const Context *, ProgramRasterState *); virtual void setupGL2(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 setPointSize(float s); + void setCullMode(RsCullMode mode); protected: bool mPointSmooth; bool mLineSmooth; bool mPointSprite; - - float mPointSize; float mLineWidth; - - + RsCullMode mCull; }; class ProgramRasterState @@ -56,7 +55,7 @@ class ProgramRasterState public: ProgramRasterState(); ~ProgramRasterState(); - void init(Context *rsc, int32_t w, int32_t h); + void init(Context *rsc); void deinit(Context *rsc); ObjectBaseRef<ProgramRaster> mDefault; diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramStore.cpp index 8a2157f..586a89f 100644 --- a/libs/rs/rsProgramFragmentStore.cpp +++ b/libs/rs/rsProgramStore.cpp @@ -14,17 +14,23 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include "rsProgramFragmentStore.h" - #include <GLES/gl.h> #include <GLES/glext.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGl/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsProgramStore.h" using namespace android; using namespace android::renderscript; -ProgramFragmentStore::ProgramFragmentStore(Context *rsc) : +ProgramStore::ProgramStore(Context *rsc) : Program(rsc) { mAllocFile = __FILE__; @@ -46,11 +52,11 @@ ProgramFragmentStore::ProgramFragmentStore(Context *rsc) : } -ProgramFragmentStore::~ProgramFragmentStore() +ProgramStore::~ProgramStore() { } -void ProgramFragmentStore::setupGL(const Context *rsc, ProgramFragmentStoreState *state) +void ProgramStore::setupGL2(const Context *rsc, ProgramStoreState *state) { if (state->mLast.get() == this) { return; @@ -70,47 +76,23 @@ void ProgramFragmentStore::setupGL(const Context *rsc, ProgramFragmentStoreState //LOGE("pfs %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc); - glDepthMask(mDepthWriteEnable); - if(mDepthTestEnable || mDepthWriteEnable) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(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 (mDitherEnable) { - glEnable(GL_DITHER); + if (rsc->mUserSurfaceConfig.stencilMin > 0) { } else { - glDisable(GL_DITHER); - } -} - -void ProgramFragmentStore::setupGL2(const Context *rsc, ProgramFragmentStoreState *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); - - glDepthMask(mDepthWriteEnable); - if(mDepthTestEnable || mDepthWriteEnable) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(mDepthFunc); - } else { - glDisable(GL_DEPTH_TEST); + glStencilMask(0); + glDisable(GL_STENCIL_TEST); } if (mDitherEnable) { @@ -121,12 +103,23 @@ void ProgramFragmentStore::setupGL2(const Context *rsc, ProgramFragmentStoreStat } -void ProgramFragmentStore::setDitherEnable(bool enable) +void ProgramStore::setDitherEnable(bool enable) { mDitherEnable = enable; } -void ProgramFragmentStore::setDepthFunc(RsDepthFunc func) +void ProgramStore::serialize(OStream *stream) const +{ + +} + +ProgramStore *ProgramStore::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} + + +void ProgramStore::setDepthFunc(RsDepthFunc func) { mDepthTestEnable = true; @@ -156,12 +149,12 @@ void ProgramFragmentStore::setDepthFunc(RsDepthFunc func) } } -void ProgramFragmentStore::setDepthMask(bool mask) +void ProgramStore::setDepthMask(bool mask) { mDepthWriteEnable = mask; } -void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst) +void ProgramStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst) { mBlendEnable = true; if ((src == RS_BLEND_SRC_ONE) && @@ -227,7 +220,7 @@ void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst) } } -void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a) +void ProgramStore::setColorMask(bool r, bool g, bool b, bool a) { mColorRWriteEnable = r; mColorGWriteEnable = g; @@ -236,24 +229,24 @@ void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a) } -ProgramFragmentStoreState::ProgramFragmentStoreState() +ProgramStoreState::ProgramStoreState() { mPFS = NULL; } -ProgramFragmentStoreState::~ProgramFragmentStoreState() +ProgramStoreState::~ProgramStoreState() { delete mPFS; } -void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h) +void ProgramStoreState::init(Context *rsc) { - ProgramFragmentStore *pfs = new ProgramFragmentStore(rsc); + ProgramStore *pfs = new ProgramStore(rsc); mDefault.set(pfs); } -void ProgramFragmentStoreState::deinit(Context *rsc) +void ProgramStoreState::deinit(Context *rsc) { mDefault.clear(); mLast.clear(); @@ -263,42 +256,42 @@ void ProgramFragmentStoreState::deinit(Context *rsc) namespace android { namespace renderscript { -void rsi_ProgramFragmentStoreBegin(Context * rsc, RsElement in, RsElement out) +void rsi_ProgramStoreBegin(Context * rsc, RsElement in, RsElement out) { delete rsc->mStateFragmentStore.mPFS; - rsc->mStateFragmentStore.mPFS = new ProgramFragmentStore(rsc); + rsc->mStateFragmentStore.mPFS = new ProgramStore(rsc); } -void rsi_ProgramFragmentStoreDepthFunc(Context *rsc, RsDepthFunc func) +void rsi_ProgramStoreDepthFunc(Context *rsc, RsDepthFunc func) { rsc->mStateFragmentStore.mPFS->setDepthFunc(func); } -void rsi_ProgramFragmentStoreDepthMask(Context *rsc, bool mask) +void rsi_ProgramStoreDepthMask(Context *rsc, bool mask) { rsc->mStateFragmentStore.mPFS->setDepthMask(mask); } -void rsi_ProgramFragmentStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a) +void rsi_ProgramStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a) { rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a); } -void rsi_ProgramFragmentStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst) +void rsi_ProgramStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst) { rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst); } -RsProgramFragmentStore rsi_ProgramFragmentStoreCreate(Context *rsc) +RsProgramStore rsi_ProgramStoreCreate(Context *rsc) { - ProgramFragmentStore *pfs = rsc->mStateFragmentStore.mPFS; + ProgramStore *pfs = rsc->mStateFragmentStore.mPFS; pfs->incUserRef(); rsc->mStateFragmentStore.mPFS = 0; return pfs; } -void rsi_ProgramFragmentStoreDither(Context *rsc, bool enable) +void rsi_ProgramStoreDither(Context *rsc, bool enable) { rsc->mStateFragmentStore.mPFS->setDitherEnable(enable); } diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramStore.h index 3412c99..95bcf3c 100644 --- a/libs/rs/rsProgramFragmentStore.h +++ b/libs/rs/rsProgramStore.h @@ -18,21 +18,21 @@ #define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H #include "rsProgram.h" +#include "rsStream.h" // --------------------------------------------------------------------------- namespace android { namespace renderscript { -class ProgramFragmentStoreState; +class ProgramStoreState; -class ProgramFragmentStore : public Program +class ProgramStore : public Program { public: - ProgramFragmentStore(Context *); - virtual ~ProgramFragmentStore(); + ProgramStore(Context *); + virtual ~ProgramStore(); - virtual void setupGL(const Context *, ProgramFragmentStoreState *); - virtual void setupGL2(const Context *, ProgramFragmentStoreState *); + virtual void setupGL2(const Context *, ProgramStoreState *); void setDepthFunc(RsDepthFunc); void setDepthMask(bool); @@ -42,6 +42,10 @@ public: void setDitherEnable(bool); + 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; @@ -60,19 +64,19 @@ protected: bool mStencilTestEnable; }; -class ProgramFragmentStoreState +class ProgramStoreState { public: - ProgramFragmentStoreState(); - ~ProgramFragmentStoreState(); - void init(Context *rsc, int32_t w, int32_t h); + ProgramStoreState(); + ~ProgramStoreState(); + void init(Context *rsc); void deinit(Context *rsc); - ObjectBaseRef<ProgramFragmentStore> mDefault; - ObjectBaseRef<ProgramFragmentStore> mLast; + ObjectBaseRef<ProgramStore> mDefault; + ObjectBaseRef<ProgramStore> mLast; - ProgramFragmentStore *mPFS; + ProgramStore *mPFS; }; diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index a2b2df4..a785262 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -14,28 +14,24 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" -#include "rsProgramVertex.h" - #include <GLES/gl.h> #include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + +#include "rsProgramVertex.h" using namespace android; using namespace android::renderscript; -ProgramVertex::ProgramVertex(Context *rsc, bool texMat) : - Program(rsc) -{ - mAllocFile = __FILE__; - mAllocLine = __LINE__; - mTextureMatrixEnable = texMat; - mLightCount = 0; - init(rsc); -} - ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) : @@ -43,69 +39,15 @@ ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, { mAllocFile = __FILE__; mAllocLine = __LINE__; - mTextureMatrixEnable = false; - mLightCount = 0; init(rsc); } ProgramVertex::~ProgramVertex() { -} - -static void logMatrix(const char *txt, const float *f) -{ - LOGV("Matrix %s, %p", txt, f); - LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[0], f[4], f[8], f[12]); - LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[1], f[5], f[9], f[13]); - LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[2], f[6], f[10], f[14]); - LOGV("%6.4f, %6.4f, %6.4f, %6.4f", f[3], f[7], f[11], f[15]); -} - -void ProgramVertex::setupGL(const Context *rsc, ProgramVertexState *state) -{ - if ((state->mLast.get() == this) && !mDirty) { - return; - } - state->mLast.set(this); - - const float *f = static_cast<const float *>(mConstants[0]->getPtr()); - - glMatrixMode(GL_TEXTURE); - if (mTextureMatrixEnable) { - glLoadMatrixf(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]); - } else { - glLoadIdentity(); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (mLightCount) { - int v = 0; - glEnable(GL_LIGHTING); - glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v); - for (uint32_t ct = 0; ct < mLightCount; ct++) { - const Light *l = mLights[ct].get(); - glEnable(GL_LIGHT0 + ct); - l->setupGL(ct); - } - for (uint32_t ct = mLightCount; ct < MAX_LIGHTS; ct++) { - glDisable(GL_LIGHT0 + ct); - } - } else { - glDisable(GL_LIGHTING); - } - - if (!f) { - LOGE("Must bind constants to vertex program"); + if(mShaderID) { + mRSC->mShaderCache.cleanupVertex(mShaderID); } - - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]); - - mDirty = false; } void ProgramVertex::loadShader(Context *rsc) { @@ -114,42 +56,19 @@ void ProgramVertex::loadShader(Context *rsc) { void ProgramVertex::createShader() { - mShader.setTo(""); - - mShader.append("varying vec4 varColor;\n"); - mShader.append("varying vec4 varTex0;\n"); - if (mUserShader.length() > 1) { - mShader.append("uniform mat4 "); - mShader.append(mUniformNames[0]); - mShader.append(";\n"); - - 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); - - // Cannot be complex - rsAssert(!f->getFieldCount()); - 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(e->getFieldName(field)); - mShader.append(";\n"); - } - } + 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()); @@ -162,149 +81,121 @@ void ProgramVertex::createShader() rsAssert(0); } - mShader.append(e->getFieldName(field)); + mShader.append(fn); mShader.append(";\n"); } } mShader.append(mUserShader); } else { - mShader.append("attribute vec4 ATTRIB_LegacyPosition;\n"); - mShader.append("attribute vec4 ATTRIB_LegacyColor;\n"); - mShader.append("attribute vec3 ATTRIB_LegacyNormal;\n"); - mShader.append("attribute float ATTRIB_LegacyPointSize;\n"); - mShader.append("attribute vec4 ATTRIB_LegacyTexture;\n"); - - for (uint32_t ct=0; ct < mUniformCount; ct++) { - mShader.append("uniform mat4 "); - mShader.append(mUniformNames[ct]); - mShader.append(";\n"); - } - - mShader.append("void main() {\n"); - mShader.append(" gl_Position = UNI_MVP * ATTRIB_LegacyPosition;\n"); - mShader.append(" gl_PointSize = ATTRIB_LegacyPointSize;\n"); - - mShader.append(" varColor = ATTRIB_LegacyColor;\n"); - if (mTextureMatrixEnable) { - mShader.append(" varTex0 = UNI_TexMatrix * ATTRIB_LegacyTexture;\n"); - } else { - mShader.append(" varTex0 = ATTRIB_LegacyTexture;\n"); - } - //mShader.append(" pos.x = pos.x / 480.0;\n"); - //mShader.append(" pos.y = pos.y / 800.0;\n"); - //mShader.append(" gl_Position = pos;\n"); - mShader.append("}\n"); + LOGE("ProgramFragment::createShader cannot create program, shader code not defined"); + rsAssert(0); } } -void ProgramVertex::setupGL2(const Context *rsc, ProgramVertexState *state, ShaderCache *sc) +void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) { //LOGE("sgl2 vtx1 %x", glGetError()); if ((state->mLast.get() == this) && !mDirty) { - //return; + return; } rsc->checkError("ProgramVertex::setupGL2 start"); - glVertexAttrib4f(1, state->color[0], state->color[1], state->color[2], state->color[3]); - - const float *f = static_cast<const float *>(mConstants[0]->getPtr()); - - Matrix mvp; - mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); - Matrix t; - t.load(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]); - mvp.multiply(&t); - - glUniformMatrix4fv(sc->vtxUniformSlot(0), 1, GL_FALSE, mvp.m); - if (mTextureMatrixEnable) { - glUniformMatrix4fv(sc->vtxUniformSlot(1), 1, GL_FALSE, - &f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]); - } - rsc->checkError("ProgramVertex::setupGL2 begin uniforms"); - uint32_t uidx = 1; - for (uint32_t ct=0; ct < mConstantCount; ct++) { - Allocation *alloc = mConstants[ct+1].get(); - if (!alloc) { - continue; + if(!isUserProgram()) { + if(mConstants[0].get() == NULL) { + LOGE("Unable to set fixed function emulation matrices because allocation is missing"); + rsc->setError(RS_ERROR_BAD_SHADER, "Fixed function allocation missing"); + return; } - - 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); - uint32_t offset = e->getFieldOffsetBytes(field); - int32_t slot = sc->vtxUniformSlot(uidx); - - const float *fd = reinterpret_cast<const float *>(&data[offset]); - - //LOGE("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i", slot, offset, ct, field, uidx); - if (slot >= 0) { - switch(f->getComponent().getVectorSize()) { - case 1: - //LOGE("Uniform 1 = %f", fd[0]); - glUniform1fv(slot, 1, fd); - break; - case 2: - //LOGE("Uniform 2 = %f %f", fd[0], fd[1]); - glUniform2fv(slot, 1, fd); - break; - case 3: - //LOGE("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); - glUniform3fv(slot, 1, fd); - break; - case 4: - //LOGE("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); - glUniform4fv(slot, 1, fd); - break; - default: - rsAssert(0); - } - } - uidx ++; + float *f = static_cast<float *>(mConstants[0]->getPtr()); + Matrix mvp; + mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); + Matrix t; + t.load(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]); + mvp.multiply(&t); + for(uint32_t i = 0; i < 16; i ++) { + f[RS_PROGRAM_VERTEX_MVP_OFFSET + i] = mvp.m[i]; } } - for (uint32_t ct=0; ct < mConstantCount; ct++) { - uint32_t glSlot = sc->vtxUniformSlot(ct + 1); - - } + rsc->checkError("ProgramVertex::setupGL2 begin uniforms"); + setupUserConstants(rsc, sc, false); state->mLast.set(this); rsc->checkError("ProgramVertex::setupGL2"); } -void ProgramVertex::addLight(const Light *l) +void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const { - if (mLightCount < MAX_LIGHTS) { - mLights[mLightCount].set(l); - mLightCount++; + if(isUserProgram()) { + LOGE("Attempting to set fixed function emulation matrix projection on user program"); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set emulation matrix on user shader"); + return; + } + if(mConstants[0].get() == NULL) { + LOGE("Unable to set fixed function emulation matrix projection because allocation is missing"); + return; } -} - -void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const -{ float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } -void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const +void ProgramVertex::setModelviewMatrix(Context *rsc, const rsc_Matrix *m) const { + if(isUserProgram()) { + LOGE("Attempting to set fixed function emulation matrix modelview on user program"); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set emulation matrix on user shader"); + return; + } + if(mConstants[0].get() == NULL) { + LOGE("Unable to set fixed function emulation matrix modelview because allocation is missing"); + rsc->setError(RS_ERROR_BAD_SHADER, "Fixed function allocation missing"); + return; + } float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } -void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const +void ProgramVertex::setTextureMatrix(Context *rsc, const rsc_Matrix *m) const { + if(isUserProgram()) { + LOGE("Attempting to set fixed function emulation matrix texture on user program"); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set emulation matrix on user shader"); + return; + } + if(mConstants[0].get() == NULL) { + LOGE("Unable to set fixed function emulation matrix texture because allocation is missing"); + rsc->setError(RS_ERROR_BAD_SHADER, "Fixed function allocation missing"); + return; + } float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } -void ProgramVertex::transformToScreen(const Context *rsc, float *v4out, const float *v3in) const +void ProgramVertex::getProjectionMatrix(Context *rsc, rsc_Matrix *m) const +{ + if(isUserProgram()) { + LOGE("Attempting to get fixed function emulation matrix projection on user program"); + rsc->setError(RS_ERROR_BAD_SHADER, "Cannot get emulation matrix on user shader"); + return; + } + if(mConstants[0].get() == NULL) { + LOGE("Unable to get fixed function emulation matrix projection because allocation is missing"); + rsc->setError(RS_ERROR_BAD_SHADER, "Fixed function allocation missing"); + return; + } + float *f = static_cast<float *>(mConstants[0]->getPtr()); + memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix)); +} + +void ProgramVertex::transformToScreen(Context *rsc, float *v4out, const float *v3in) const { + if(isUserProgram()) { + return; + } float *f = static_cast<float *>(mConstants[0]->getPtr()); Matrix mvp; mvp.loadMultiply((Matrix *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], @@ -312,45 +203,31 @@ void ProgramVertex::transformToScreen(const Context *rsc, float *v4out, const fl mvp.vectorMultiply(v4out, v3in); } -void ProgramVertex::initAddUserElement(const Element *e, String8 *names, 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, count, prefix); - } else { - String8 tmp(prefix); - tmp.append(e->getFieldName(ct)); - names[*count].setTo(tmp.string()); - (*count)++; - } - } -} - - void ProgramVertex::init(Context *rsc) { mAttribCount = 0; if (mUserShader.size() > 0) { for (uint32_t ct=0; ct < mInputCount; ct++) { - initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, "ATTRIB_"); + initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, RS_SHADER_ATTR); } - - mUniformCount = 1; - mUniformNames[0].setTo("UNI_MVP"); + mUniformCount = 0; for (uint32_t ct=0; ct < mConstantCount; ct++) { - initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_"); + initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, RS_SHADER_UNI); } - } else { - mUniformCount = 2; - mUniformNames[0].setTo("UNI_MVP"); - mUniformNames[1].setTo("UNI_TexMatrix"); } - createShader(); } +void ProgramVertex::serialize(OStream *stream) const +{ + +} + +ProgramVertex *ProgramVertex::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} + /////////////////////////////////////////////////////////////////////// @@ -362,44 +239,80 @@ ProgramVertexState::~ProgramVertexState() { } -void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h) +void ProgramVertexState::init(Context *rsc) { - RsElement e = (RsElement) Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1); - - rsi_TypeBegin(rsc, e); - rsi_TypeAdd(rsc, RS_DIMENSION_X, 48); - mAllocType.set((Type *)rsi_TypeCreate(rsc)); + const Element *matrixElem = Element::create(rsc, RS_TYPE_MATRIX_4X4, RS_KIND_USER, false, 1); + const Element *f2Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); + const Element *f3Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); + const Element *f4Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); + + rsc->mStateElement.elementBuilderBegin(); + rsc->mStateElement.elementBuilderAdd(matrixElem, "MV", 1); + rsc->mStateElement.elementBuilderAdd(matrixElem, "P", 1); + rsc->mStateElement.elementBuilderAdd(matrixElem, "TexMatrix", 1); + rsc->mStateElement.elementBuilderAdd(matrixElem, "MVP", 1); + const Element *constInput = rsc->mStateElement.elementBuilderCreate(rsc); + + rsc->mStateElement.elementBuilderBegin(); + rsc->mStateElement.elementBuilderAdd(f4Elem, "position", 1); + rsc->mStateElement.elementBuilderAdd(f4Elem, "color", 1); + rsc->mStateElement.elementBuilderAdd(f3Elem, "normal", 1); + rsc->mStateElement.elementBuilderAdd(f2Elem, "texture0", 1); + const Element *attrElem = rsc->mStateElement.elementBuilderCreate(rsc); + + Type *inputType = new Type(rsc); + inputType->setElement(constInput); + inputType->setDimX(1); + inputType->compute(); + + String8 shaderString(RS_SHADER_INTERNAL); + shaderString.append("varying vec4 varColor;\n"); + shaderString.append("varying vec2 varTex0;\n"); + shaderString.append("void main() {\n"); + shaderString.append(" gl_Position = UNI_MVP * ATTRIB_position;\n"); + shaderString.append(" gl_PointSize = 1.0;\n"); + shaderString.append(" varColor = ATTRIB_color;\n"); + shaderString.append(" varTex0 = ATTRIB_texture0;\n"); + shaderString.append("}\n"); + + uint32_t tmp[6]; + tmp[0] = RS_PROGRAM_PARAM_CONSTANT; + tmp[1] = (uint32_t)inputType; + tmp[2] = RS_PROGRAM_PARAM_INPUT; + tmp[3] = (uint32_t)attrElem; + tmp[4] = RS_PROGRAM_PARAM_TEXTURE_COUNT; + tmp[5] = 0; + + ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), + shaderString.length(), tmp, 6); + Allocation *alloc = new Allocation(rsc, inputType); + pv->bindAllocation(rsc, alloc, 0); - ProgramVertex *pv = new ProgramVertex(rsc, false); - Allocation *alloc = (Allocation *)rsi_AllocationCreateTyped(rsc, mAllocType.get()); mDefaultAlloc.set(alloc); mDefault.set(pv); - pv->init(rsc); - pv->bindAllocation(alloc, 0); - color[0] = 1.f; - color[1] = 1.f; - color[2] = 1.f; - color[3] = 1.f; + updateSize(rsc); - updateSize(rsc, w, h); } -void ProgramVertexState::updateSize(Context *rsc, int32_t w, int32_t h) +void ProgramVertexState::updateSize(Context *rsc) { + float *f = static_cast<float *>(mDefaultAlloc->getPtr()); + Matrix m; - m.loadOrtho(0,w, h,0, -1,1); - mDefaultAlloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0], 16*4); + 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)); m.loadIdentity(); - mDefaultAlloc->subData(RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0], 16*4); + memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m.m, sizeof(m)); + memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m.m, sizeof(m)); } void ProgramVertexState::deinit(Context *rsc) { mDefaultAlloc.clear(); mDefault.clear(); - mAllocType.clear(); mLast.clear(); } @@ -407,15 +320,7 @@ void ProgramVertexState::deinit(Context *rsc) namespace android { namespace renderscript { - -RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, bool texMat) -{ - ProgramVertex *pv = new ProgramVertex(rsc, texMat); - pv->incUserRef(); - return pv; -} - -RsProgramVertex rsi_ProgramVertexCreate2(Context *rsc, const char * shaderText, +RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength) { diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index 28554cc..355df2b 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -28,40 +28,26 @@ class ProgramVertexState; class ProgramVertex : public Program { public: - const static uint32_t MAX_LIGHTS = 8; - ProgramVertex(Context *,const char * shaderText, uint32_t shaderLength, const uint32_t * params, uint32_t paramLength); - ProgramVertex(Context *, bool texMat); virtual ~ProgramVertex(); - virtual void setupGL(const Context *rsc, ProgramVertexState *state); - virtual void setupGL2(const Context *rsc, ProgramVertexState *state, ShaderCache *sc); - - - void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;} - void addLight(const Light *); + virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc); - void setProjectionMatrix(const rsc_Matrix *) const; - void setModelviewMatrix(const rsc_Matrix *) const; - void setTextureMatrix(const rsc_Matrix *) const; + void setProjectionMatrix(Context *, const rsc_Matrix *) const; + void getProjectionMatrix(Context *, rsc_Matrix *) const; + void setModelviewMatrix(Context *, const rsc_Matrix *) const; + void setTextureMatrix(Context *, const rsc_Matrix *) const; - void transformToScreen(const Context *, float *v4out, const float *v3in) const; + void transformToScreen(Context *, float *v4out, const float *v3in) const; virtual void createShader(); virtual void loadShader(Context *); virtual void init(Context *); - -protected: - uint32_t mLightCount; - ObjectBaseRef<const Light> mLights[MAX_LIGHTS]; - - // Hacks to create a program for now - bool mTextureMatrixEnable; - -private: - void initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix); + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; } + static ProgramVertex *createFromStream(Context *rsc, IStream *stream); }; @@ -71,18 +57,13 @@ public: ProgramVertexState(); ~ProgramVertexState(); - void init(Context *rsc, int32_t w, int32_t h); + void init(Context *rsc); void deinit(Context *rsc); - void updateSize(Context *rsc, int32_t w, int32_t h); + void updateSize(Context *rsc); ObjectBaseRef<ProgramVertex> mDefault; ObjectBaseRef<ProgramVertex> mLast; ObjectBaseRef<Allocation> mDefaultAlloc; - - ObjectBaseRef<Type> mAllocType; - - - float color[4]; }; diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp index 71f508f..180d78e 100644 --- a/libs/rs/rsSampler.cpp +++ b/libs/rs/rsSampler.cpp @@ -14,10 +14,16 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include <GLES/gl.h> #include <GLES/glext.h> - #include "rsContext.h" +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#endif //ANDROID_RS_BUILD_FOR_HOST + #include "rsSampler.h" @@ -38,7 +44,8 @@ Sampler::Sampler(Context *rsc, RsSamplerValue minFilter, RsSamplerValue wrapS, RsSamplerValue wrapT, - RsSamplerValue wrapR) : ObjectBase(rsc) + RsSamplerValue wrapR, + float aniso) : ObjectBase(rsc) { mAllocFile = __FILE__; mAllocLine = __LINE__; @@ -47,13 +54,14 @@ Sampler::Sampler(Context *rsc, mWrapS = wrapS; mWrapT = wrapT; mWrapR = wrapR; + mAniso = aniso; } Sampler::~Sampler() { } -void Sampler::setupGL(const Context *rsc, bool npot) +void Sampler::setupGL(const Context *rsc, const Allocation *tex) { GLenum trans[] = { GL_NEAREST, //RS_SAMPLER_NEAREST, @@ -61,25 +69,38 @@ void Sampler::setupGL(const Context *rsc, bool npot) GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR, GL_REPEAT, //RS_SAMPLER_WRAP, GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP - }; - bool forceNonMip = false; - if (!rsc->ext_OES_texture_npot() && npot) { - forceNonMip = true; - } + 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 + }; - if ((mMinFilter == RS_SAMPLER_LINEAR_MIP_LINEAR) && forceNonMip) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (!rsc->ext_OES_texture_npot() && tex->getType()->getIsNp2()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, transNP[mMagFilter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, transNP[mWrapS]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, transNP[mWrapT]); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + if (tex->getHasGraphicsMipmaps()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, transNP[mMinFilter]); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]); + float anisoValue = rsMin(rsc->ext_texture_max_aniso(), mAniso); + if(rsc->ext_texture_max_aniso() > 1.0f) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue); + } - rsc->checkError("ProgramFragment::setupGL2 tex env"); + rsc->checkError("Sampler::setupGL2 tex env"); } void Sampler::bindToContext(SamplerState *ss, uint32_t slot) @@ -94,6 +115,17 @@ void Sampler::unbindFromContext(SamplerState *ss) mBoundSlot = -1; ss->mSamplers[slot].clear(); } + +void Sampler::serialize(OStream *stream) const +{ + +} + +Sampler *Sampler::createFromStream(Context *rsc, IStream *stream) +{ + return NULL; +} + /* void SamplerState::setupGL() { @@ -122,6 +154,7 @@ void rsi_SamplerBegin(Context *rsc) 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) @@ -144,21 +177,37 @@ void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value) 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->mWrapR, + ss->mAniso); s->incUserRef(); return s; } diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h index 0506081..4946355 100644 --- a/libs/rs/rsSampler.h +++ b/libs/rs/rsSampler.h @@ -36,22 +36,28 @@ public: RsSamplerValue minFilter, RsSamplerValue wrapS, RsSamplerValue wrapT, - RsSamplerValue wrapR); + RsSamplerValue wrapR, + float aniso = 1.0f); virtual ~Sampler(); void bind(Allocation *); - void setupGL(const Context *, bool npot); + void setupGL(const Context *, const Allocation *); void bindToContext(SamplerState *, uint32_t slot); void unbindFromContext(SamplerState *); + virtual void serialize(OStream *stream) const; + 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; int32_t mBoundSlot; @@ -70,6 +76,7 @@ public: 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 a33933b..c5632b5 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -24,17 +24,52 @@ Script::Script(Context *rsc) : ObjectBase(rsc) mAllocFile = __FILE__; mAllocLine = __LINE__; memset(&mEnviroment, 0, sizeof(mEnviroment)); - mEnviroment.mClearColor[0] = 0; - mEnviroment.mClearColor[1] = 0; - mEnviroment.mClearColor[2] = 0; - mEnviroment.mClearColor[3] = 1; - mEnviroment.mClearDepth = 1; - mEnviroment.mClearStencil = 0; - mEnviroment.mIsRoot = false; + + mSlots = NULL; + mTypes = NULL; } Script::~Script() { + if(mSlots) { + delete [] mSlots; + mSlots = NULL; + } + if(mTypes) { + delete [] mTypes; + mTypes = NULL; + } +} + +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("Script::setSlot unable to set allocation, invalid slot index"); + return; + } + + mSlots[slot].set(a); +} + +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); + //} + } } namespace android { @@ -44,71 +79,65 @@ namespace renderscript { void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint32_t slot) { Script *s = static_cast<Script *>(vs); - s->mSlots[slot].set(static_cast<Allocation *>(va)); + Allocation *a = static_cast<Allocation *>(va); + s->setSlot(slot, a); + //LOGE("rsi_ScriptBindAllocation %i %p %p", slot, a, a->getPtr()); } -void rsi_ScriptSetClearColor(Context * rsc, RsScript vs, float r, float g, float b, float a) +void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length) { Script *s = static_cast<Script *>(vs); - s->mEnviroment.mClearColor[0] = r; - s->mEnviroment.mClearColor[1] = g; - s->mEnviroment.mClearColor[2] = b; - s->mEnviroment.mClearColor[3] = a; + s->mEnviroment.mTimeZone = timeZone; } -void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length) +void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot) { Script *s = static_cast<Script *>(vs); - s->mEnviroment.mTimeZone = timeZone; + s->Invoke(rsc, slot, NULL, 0); } -void rsi_ScriptSetClearDepth(Context * rsc, RsScript vs, float v) + +void rsi_ScriptInvokeData(Context *rsc, RsScript vs, uint32_t slot, void *data) { Script *s = static_cast<Script *>(vs); - s->mEnviroment.mClearDepth = v; + s->Invoke(rsc, slot, NULL, 0); } -void rsi_ScriptSetClearStencil(Context * rsc, RsScript vs, uint32_t v) +void rsi_ScriptInvokeV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { Script *s = static_cast<Script *>(vs); - s->mEnviroment.mClearStencil = v; + s->Invoke(rsc, slot, data, len); } -void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, const char *name) +void rsi_ScriptSetVarI(Context *rsc, RsScript vs, uint32_t slot, int value) { - ScriptCState *ss = &rsc->mScriptC; - const Type *t = static_cast<const Type *>(vt); - ss->mConstantBufferTypes[slot].set(t); - ss->mSlotWritable[slot] = writable; - if (name) { - ss->mSlotNames[slot].setTo(name); - } else { - ss->mSlotNames[slot].setTo(""); - } + Script *s = static_cast<Script *>(vs); + s->setVar(slot, &value, sizeof(value)); } -void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot) +void rsi_ScriptSetVarJ(Context *rsc, RsScript vs, uint32_t slot, long long value) { - ScriptCState *ss = &rsc->mScriptC; - ss->mInvokableNames[slot] = name; + Script *s = static_cast<Script *>(vs); + s->setVar(slot, &value, sizeof(value)); } -void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot) +void rsi_ScriptSetVarF(Context *rsc, RsScript vs, uint32_t slot, float value) { Script *s = static_cast<Script *>(vs); - if (s->mEnviroment.mInvokables[slot] == NULL) { - rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); - return; - } - s->setupScript(); - s->mEnviroment.mInvokables[slot](); + s->setVar(slot, &value, sizeof(value)); } +void rsi_ScriptSetVarD(Context *rsc, RsScript vs, uint32_t slot, double value) +{ + Script *s = static_cast<Script *>(vs); + s->setVar(slot, &value, sizeof(value)); +} -void rsi_ScriptSetRoot(Context * rsc, bool isRoot) +void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { - ScriptCState *ss = &rsc->mScriptC; - ss->mScript->mEnviroment.mIsRoot = isRoot; + const float *fp = (const float *)data; + Script *s = static_cast<Script *>(vs); + s->setVar(slot, data, len); } diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index 5f4a536..c73bb5e 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -27,9 +27,7 @@ namespace renderscript { class ProgramVertex; class ProgramFragment; class ProgramRaster; -class ProgramFragmentStore; - -#define MAX_SCRIPT_BANKS 16 +class ProgramStore; class Script : public ObjectBase { @@ -39,38 +37,45 @@ public: Script(Context *); virtual ~Script(); - struct Enviroment_t { - bool mIsRoot; - float mClearColor[4]; - float mClearDepth; - uint32_t mClearStencil; - - uint32_t mStartTimeMillis; + int64_t mStartTimeMillis; + int64_t mLastDtTime; const char* mTimeZone; ObjectBaseRef<ProgramVertex> mVertex; ObjectBaseRef<ProgramFragment> mFragment; ObjectBaseRef<ProgramRaster> mRaster; - ObjectBaseRef<ProgramFragmentStore> mFragmentStore; - InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS]; + ObjectBaseRef<ProgramStore> mFragmentStore; + + uint32_t mInvokeFunctionCount; + InvokeFunc_t *mInvokeFunctions; + uint32_t mFieldCount; + void ** mFieldAddress; + char * mScriptText; uint32_t mScriptTextLength; + + bool mIsThreadable; }; Enviroment_t mEnviroment; - uint32_t mCounstantBufferCount; - - - ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS]; - ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS]; - String8 mSlotNames[MAX_SCRIPT_BANKS]; - bool mSlotWritable[MAX_SCRIPT_BANKS]; + void initSlots(); + void setSlot(uint32_t slot, Allocation *a); + void setVar(uint32_t slot, const void *val, uint32_t len); + virtual void runForEach(Context *rsc, + const Allocation * ain, + Allocation * aout, + const void * usr, + const RsScriptCall *sc = NULL) = 0; + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0; + virtual void setupScript(Context *rsc) = 0; + virtual uint32_t run(Context *) = 0; +protected: + ObjectBaseRef<Allocation> *mSlots; + ObjectBaseRef<const Type> *mTypes; - virtual void setupScript() = 0; - virtual uint32_t run(Context *, uint32_t launchID) = 0; }; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index f4d2451..a2910d7 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -17,9 +17,9 @@ #include "rsContext.h" #include "rsScriptC.h" #include "rsMatrix.h" - -#include "acc/acc.h" +#include "../../compile/libbcc/include/bcc/bcc.h" #include "utils/Timers.h" +#include "utils/StopWatch.h" #include <GLES/gl.h> #include <GLES/glext.h> @@ -37,40 +37,86 @@ ScriptC::ScriptC(Context *rsc) : Script(rsc) { mAllocFile = __FILE__; mAllocLine = __LINE__; - mAccScript = NULL; + mBccScript = NULL; memset(&mProgram, 0, sizeof(mProgram)); } ScriptC::~ScriptC() { - if (mAccScript) { - accDeleteScript(mAccScript); + if (mBccScript) { + bccDeleteScript(mBccScript); } free(mEnviroment.mScriptText); mEnviroment.mScriptText = NULL; } -void ScriptC::setupScript() +void ScriptC::setupScript(Context *rsc) { - for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - if (mProgram.mSlotPointers[ct]) { - *mProgram.mSlotPointers[ct] = mSlots[ct]->getPtr(); + setupGLState(rsc); + mEnviroment.mStartTimeMillis + = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); + + for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + if (mSlots[ct].get() && !mTypes[ct].get()) { + mTypes[ct].set(mSlots[ct]->getType()); + } + + if (!mTypes[ct].get()) + continue; + void *ptr = NULL; + if (mSlots[ct].get()) { + ptr = mSlots[ct]->getPtr(); + } + void **dest = ((void ***)mEnviroment.mFieldAddress)[ct]; + + if (rsc->props.mLogScripts) { + LOGV("%p ScriptC::setupScript slot=%i dst=%p src=%p type=%p", rsc, ct, dest, ptr, mSlots[ct]->getType()); + + //const uint32_t *p32 = (const uint32_t *)ptr; + //for (uint32_t ct2=0; ct2 < mSlots[ct]->getType()->getDimX(); ct2++) { + //LOGE(" %i = 0x%08x ", ct2, p32[ct2]); + //} + } + + if (dest) { + *dest = ptr; + } else { + if (rsc->props.mLogScripts) { + LOGV("ScriptC::setupScript, NULL var binding address."); + } } } } - -uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex) +const Allocation *ScriptC::ptrToAllocation(const void *ptr) const { - if (mProgram.mScript == NULL) { - rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); - return 0; + if (!ptr) { + return NULL; + } + for (uint32_t ct=0; ct < mEnviroment.mFieldCount; ct++) { + if (!mSlots[ct].get()) + continue; + if (mSlots[ct]->getPtr() == ptr) { + return mSlots[ct].get(); + } } + LOGE("ScriptC::ptrToAllocation, failed to find %p", ptr); + return NULL; +} - Context::ScriptTLSStruct * tls = - (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); +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->setFragmentStore(mEnviroment.mFragmentStore.get()); } @@ -83,51 +129,262 @@ uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex) if (mEnviroment.mRaster.get()) { rsc->setRaster(mEnviroment.mRaster.get()); } +} - if (launchIndex == 0) { - mEnviroment.mStartTimeMillis - = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); +uint32_t ScriptC::run(Context *rsc) +{ + if (mProgram.mRoot == NULL) { + rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script"); + return 0; } - setupScript(); + + setupScript(rsc); uint32_t ret = 0; - tls->mScript = this; - ret = mProgram.mScript(launchIndex); - tls->mScript = NULL; + Script * oldTLS = setTLS(this); + + if (rsc->props.mLogScripts) { + LOGV("%p ScriptC::run invoking root, ptr %p", rsc, mProgram.mRoot); + } + + ret = mProgram.mRoot(); + + if (rsc->props.mLogScripts) { + LOGV("%p ScriptC::run invoking complete, ret=%i", rsc, ret); + } + + setTLS(oldTLS); return ret; } -ScriptCState::ScriptCState() + +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) { - mScript = NULL; - clear(); + 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; + } + } + } + } -ScriptCState::~ScriptCState() +void ScriptC::runForEach(Context *rsc, + const Allocation * ain, + Allocation * aout, + const void * usr, + const RsScriptCall *sc) { - delete mScript; - mScript = NULL; + 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->getType()->getDimZ() == 0); + + 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 && (mtls.dimY > 1)) { + + //LOGE("launch 1"); + rsc->launchThreads(wc_xy, &mtls); + } 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); } -void ScriptCState::clear() +void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) { - for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - mConstantBufferTypes[ct].clear(); - mSlotNames[ct].setTo(""); - mInvokableNames[ct].setTo(""); - mSlotWritable[ct] = false; + //LOGE("rsi_ScriptInvoke %i", slot); + if ((slot >= mEnviroment.mInvokeFunctionCount) || + (mEnviroment.mInvokeFunctions[slot] == NULL)) { + rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script"); + return; } + setupScript(rsc); + Script * oldTLS = setTLS(this); - delete mScript; - mScript = new ScriptC(NULL); + 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); + } + + setTLS(oldTLS); +} - mInt32Defines.clear(); - mFloatDefines.clear(); +ScriptCState::ScriptCState() +{ + mScript.clear(); } -static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) +ScriptCState::~ScriptCState() { - const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name); + mScript.clear(); +} + +void ScriptCState::init(Context *rsc) +{ + clear(rsc); +} + +void ScriptCState::clear(Context *rsc) +{ + rsAssert(rsc); + mScript.clear(); + mScript.set(new ScriptC(rsc)); +} + +static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) +{ + const ScriptCState::SymbolTable_t *sym; + ScriptC *s = (ScriptC *)pContext; + sym = ScriptCState::lookupSymbol(name); + if (sym) { + return sym->mPtr; + } + sym = ScriptCState::lookupSymbolCL(name); + if (sym) { + return sym->mPtr; + } + s->mEnviroment.mIsThreadable = false; + sym = ScriptCState::lookupSymbolGL(name); if (sym) { return sym->mPtr; } @@ -137,65 +394,53 @@ static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) void ScriptCState::runCompiler(Context *rsc, ScriptC *s) { - s->mAccScript = accCreateScript(); - String8 tmp; - - rsc->appendNameDefines(&tmp); - appendDecls(&tmp); - appendVarDefines(rsc, &tmp); - appendTypes(rsc, &tmp); - tmp.append("#line 1\n"); - - const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText}; - int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ; - accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength); - accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL); - accCompileScript(s->mAccScript); - accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript); - accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit); - rsAssert(s->mProgram.mScript); - - if (!s->mProgram.mScript) { - ACCchar buf[4096]; - ACCsizei len; - accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf); - LOGE("%s", buf); - rsc->setError(RS_ERROR_BAD_SCRIPT, "Error compiling user script."); - return; + LOGV("%p ScriptCState::runCompiler ", rsc); + { + StopWatch compileTimer("RenderScript compile time"); + s->mBccScript = bccCreateScript(); + s->mEnviroment.mIsThreadable = true; + bccScriptBitcode(s->mBccScript, s->mEnviroment.mScriptText, s->mEnviroment.mScriptTextLength); + bccRegisterSymbolCallback(s->mBccScript, symbolLookup, s); + bccCompileScript(s->mBccScript); + bccGetScriptLabel(s->mBccScript, "root", (BCCvoid**) &s->mProgram.mRoot); + bccGetScriptLabel(s->mBccScript, "init", (BCCvoid**) &s->mProgram.mInit); } + LOGV("%p ScriptCState::runCompiler root %p, init %p", rsc, s->mProgram.mRoot, s->mProgram.mInit); if (s->mProgram.mInit) { s->mProgram.mInit(); } - for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - if (mSlotNames[ct].length() > 0) { - accGetScriptLabel(s->mAccScript, - mSlotNames[ct].string(), - (ACCvoid**) &s->mProgram.mSlotPointers[ct]); - } + bccGetExportFuncs(s->mBccScript, (BCCsizei*) &s->mEnviroment.mInvokeFunctionCount, 0, NULL); + if(s->mEnviroment.mInvokeFunctionCount <= 0) + s->mEnviroment.mInvokeFunctions = NULL; + else { + s->mEnviroment.mInvokeFunctions = (Script::InvokeFunc_t*) calloc(s->mEnviroment.mInvokeFunctionCount, sizeof(Script::InvokeFunc_t)); + bccGetExportFuncs(s->mBccScript, NULL, s->mEnviroment.mInvokeFunctionCount, (BCCvoid **) s->mEnviroment.mInvokeFunctions); } - for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - if (mInvokableNames[ct].length() > 0) { - accGetScriptLabel(s->mAccScript, - mInvokableNames[ct].string(), - (ACCvoid**) &s->mEnviroment.mInvokables[ct]); - } + bccGetExportVars(s->mBccScript, (BCCsizei*) &s->mEnviroment.mFieldCount, 0, NULL); + if(s->mEnviroment.mFieldCount <= 0) + s->mEnviroment.mFieldAddress = NULL; + else { + s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *)); + bccGetExportVars(s->mBccScript, NULL, s->mEnviroment.mFieldCount, (BCCvoid **) s->mEnviroment.mFieldAddress); + s->initSlots(); } s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); - s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore()); + s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramStore()); s->mEnviroment.mRaster.set(rsc->getDefaultProgramRaster()); - if (s->mProgram.mScript) { + if (s->mProgram.mRoot) { const static int pragmaMax = 16; - ACCsizei pragmaCount; - ACCchar * str[pragmaMax]; - accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]); + BCCsizei pragmaCount; + BCCchar * str[pragmaMax]; + bccGetPragmas(s->mBccScript, &pragmaCount, pragmaMax, &str[0]); for (int ct=0; ct < pragmaCount; ct+=2) { + //LOGE("pragme %s %s", str[ct], str[ct+1]); if (!strcmp(str[ct], "version")) { continue; } @@ -208,11 +453,6 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) s->mEnviroment.mVertex.clear(); continue; } - ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]); - if (pv != NULL) { - s->mEnviroment.mVertex.set(pv); - continue; - } LOGE("Unreconized value %s passed to stateVertex", str[ct+1]); } @@ -224,11 +464,6 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) s->mEnviroment.mRaster.clear(); continue; } - ProgramRaster * pr = (ProgramRaster *)rsc->lookupName(str[ct+1]); - if (pr != NULL) { - s->mEnviroment.mRaster.set(pr); - continue; - } LOGE("Unreconized value %s passed to stateRaster", str[ct+1]); } @@ -240,11 +475,6 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) s->mEnviroment.mFragment.clear(); continue; } - ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]); - if (pf != NULL) { - s->mEnviroment.mFragment.set(pf); - continue; - } LOGE("Unreconized value %s passed to stateFragment", str[ct+1]); } @@ -256,12 +486,6 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) s->mEnviroment.mFragmentStore.clear(); continue; } - ProgramFragmentStore * pfs = - (ProgramFragmentStore *)rsc->lookupName(str[ct+1]); - if (pfs != NULL) { - s->mEnviroment.mFragmentStore.set(pfs); - continue; - } LOGE("Unreconized value %s passed to stateStore", str[ct+1]); } @@ -273,111 +497,6 @@ void ScriptCState::runCompiler(Context *rsc, ScriptC *s) } } -static void appendElementBody(String8 *s, const Element *e) -{ - s->append(" {\n"); - for (size_t ct2=0; ct2 < e->getFieldCount(); ct2++) { - const Element *c = e->getField(ct2); - s->append(" "); - s->append(c->getCType()); - s->append(" "); - s->append(e->getFieldName(ct2)); - s->append(";\n"); - } - s->append("}"); -} - -void ScriptCState::appendVarDefines(const Context *rsc, String8 *str) -{ - char buf[256]; - if (rsc->props.mLogScripts) { - LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n", - mInt32Defines.size(), mFloatDefines.size()); - } - for (size_t ct=0; ct < mInt32Defines.size(); ct++) { - str->append("#define "); - str->append(mInt32Defines.keyAt(ct)); - str->append(" "); - sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct)); - str->append(buf); - } - for (size_t ct=0; ct < mFloatDefines.size(); ct++) { - str->append("#define "); - str->append(mFloatDefines.keyAt(ct)); - str->append(" "); - sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct)); - str->append(buf); - } -} - - - -void ScriptCState::appendTypes(const Context *rsc, String8 *str) -{ - char buf[256]; - String8 tmp; - - str->append("struct vecF32_2_s {float x; float y;};\n"); - str->append("struct vecF32_3_s {float x; float y; float z;};\n"); - str->append("struct vecF32_4_s {float x; float y; float z; float w;};\n"); - str->append("struct vecU8_4_s {char r; char g; char b; char a;};\n"); - str->append("#define vecF32_2_t struct vecF32_2_s\n"); - str->append("#define vecF32_3_t struct vecF32_3_s\n"); - str->append("#define vecF32_4_t struct vecF32_4_s\n"); - str->append("#define vecU8_4_t struct vecU8_4_s\n"); - str->append("#define vecI8_4_t struct vecU8_4_s\n"); - - for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - const Type *t = mConstantBufferTypes[ct].get(); - if (!t) { - continue; - } - const Element *e = t->getElement(); - if (e->getName() && (e->getFieldCount() > 1)) { - String8 s("struct struct_"); - s.append(e->getName()); - s.append(e->getCStructBody()); - s.append(";\n"); - - s.append("#define "); - s.append(e->getName()); - s.append("_t struct struct_"); - s.append(e->getName()); - s.append("\n\n"); - if (rsc->props.mLogScripts) { - LOGV("%s", static_cast<const char*>(s)); - } - str->append(s); - } - - if (mSlotNames[ct].length() > 0) { - String8 s; - if (e->getName()) { - // Use the named struct - s.setTo(e->getName()); - } else { - // create an struct named from the slot. - s.setTo("struct "); - s.append(mSlotNames[ct]); - s.append("_s"); - s.append(e->getCStructBody()); - //appendElementBody(&s, e); - s.append(";\n"); - s.append("struct "); - s.append(mSlotNames[ct]); - s.append("_s"); - } - - s.append(" * "); - s.append(mSlotNames[ct]); - s.append(";\n"); - if (rsc->props.mLogScripts) { - LOGV("%s", static_cast<const char*>(s)); - } - str->append(s); - } - } -} namespace android { @@ -386,14 +505,7 @@ namespace renderscript { void rsi_ScriptCBegin(Context * rsc) { ScriptCState *ss = &rsc->mScriptC; - ss->clear(); -} - -void rsi_ScriptCSetScript(Context * rsc, void *vp) -{ - rsAssert(0); - //ScriptCState *ss = &rsc->mScriptC; - //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp); + ss->clear(rsc); } void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) @@ -412,32 +524,13 @@ RsScript rsi_ScriptCCreate(Context * rsc) { ScriptCState *ss = &rsc->mScriptC; - ScriptC *s = ss->mScript; - ss->mScript = NULL; + ObjectBaseRef<ScriptC> s = ss->mScript.get(); + ss->mScript.clear(); - ss->runCompiler(rsc, s); + ss->runCompiler(rsc, s.get()); s->incUserRef(); - s->setContext(rsc); - for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { - s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get()); - s->mSlotNames[ct] = ss->mSlotNames[ct]; - s->mSlotWritable[ct] = ss->mSlotWritable[ct]; - } - - ss->clear(); - return s; -} - -void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value) -{ - ScriptCState *ss = &rsc->mScriptC; - ss->mFloatDefines.add(String8(name), value); -} - -void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value) -{ - ScriptCState *ss = &rsc->mScriptC; - ss->mInt32Defines.add(String8(name), value); + ss->clear(rsc); + return s.get(); } } diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 35abadf..e5b5ba9 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -21,9 +21,7 @@ #include "RenderScriptEnv.h" -#include <utils/KeyedVector.h> - -struct ACCscript; +struct BCCscript; // --------------------------------------------------------------------------- namespace android { @@ -34,7 +32,7 @@ namespace renderscript { class ScriptC : public Script { public: - typedef int (*RunScript_t)(uint32_t launchIndex); + typedef int (*RunScript_t)(); typedef void (*VoidFunc_t)(); ScriptC(Context *); @@ -44,18 +42,35 @@ public: int mVersionMajor; int mVersionMinor; - RunScript_t mScript; + RunScript_t mRoot; VoidFunc_t mInit; - - void ** mSlotPointers[MAX_SCRIPT_BANKS]; }; Program_t mProgram; - ACCscript* mAccScript; + BCCscript* mBccScript; + + const Allocation *ptrToAllocation(const void *) const; + + + virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len); - virtual void setupScript(); - virtual uint32_t run(Context *, uint32_t launchID); + virtual uint32_t run(Context *); + + virtual void runForEach(Context *rsc, + const Allocation * ain, + Allocation * aout, + const void * usr, + 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: + void setupScript(Context *); + void setupGLState(Context *); + Script * setTLS(Script *); }; class ScriptCState @@ -64,30 +79,21 @@ public: ScriptCState(); ~ScriptCState(); - ScriptC *mScript; + ObjectBaseRef<ScriptC> mScript; - ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS]; - String8 mSlotNames[MAX_SCRIPT_BANKS]; - bool mSlotWritable[MAX_SCRIPT_BANKS]; - String8 mInvokableNames[MAX_SCRIPT_BANKS]; + void init(Context *rsc); - void clear(); + void clear(Context *rsc); void runCompiler(Context *rsc, ScriptC *s); - void appendVarDefines(const Context *rsc, String8 *str); - void appendTypes(const Context *rsc, String8 *str); struct SymbolTable_t { const char * mName; void * mPtr; - const char * mRet; - const char * mParam; }; - static SymbolTable_t gSyms[]; + //static SymbolTable_t gSyms[]; static const SymbolTable_t * lookupSymbol(const char *); - static void appendDecls(String8 *str); - - KeyedVector<String8,int> mInt32Defines; - KeyedVector<String8,float> mFloatDefines; + static const SymbolTable_t * lookupSymbolCL(const char *); + static const SymbolTable_t * lookupSymbolGL(const char *); }; diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index 202ca3d..e0de867 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -17,18 +17,9 @@ #include "rsContext.h" #include "rsScriptC.h" #include "rsMatrix.h" -#include "rsNoise.h" -#include "acc/acc.h" #include "utils/Timers.h" -#define GL_GLEXT_PROTOTYPES - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - #include <time.h> using namespace android; @@ -39,252 +30,11 @@ using namespace android::renderscript; Context * rsc = tls->mContext; \ ScriptC * sc = (ScriptC *) tls->mScript -typedef struct { - float x; - float y; - float z; -} vec3_t; - -typedef struct { - float x; - float y; - float z; - float w; -} vec4_t; - -typedef struct { - float x; - float y; -} vec2_t; - -////////////////////////////////////////////////////////////////////////////// -// IO routines -////////////////////////////////////////////////////////////////////////////// - -static float SC_loadF(uint32_t bank, uint32_t offset) -{ - GET_TLS(); - const void *vp = sc->mSlots[bank]->getPtr(); - const float *f = static_cast<const float *>(vp); - //LOGE("loadF %i %i = %f %x", bank, offset, f, ((int *)&f)[0]); - return f[offset]; -} - -static int32_t SC_loadI32(uint32_t bank, uint32_t offset) -{ - GET_TLS(); - const void *vp = sc->mSlots[bank]->getPtr(); - const int32_t *i = static_cast<const int32_t *>(vp); - //LOGE("loadI32 %i %i = %i", bank, offset, t); - return i[offset]; -} - -static float* SC_loadArrayF(uint32_t bank, uint32_t offset) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - float *f = static_cast<float *>(vp); - return f + offset; -} - -static int32_t* SC_loadArrayI32(uint32_t bank, uint32_t offset) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - int32_t *i = static_cast<int32_t *>(vp); - return i + offset; -} - -static float* SC_loadSimpleMeshVerticesF(RsSimpleMesh mesh, uint32_t idx) -{ - SimpleMesh *tm = static_cast<SimpleMesh *>(mesh); - void *vp = tm->mVertexBuffers[idx]->getPtr();; - return static_cast<float *>(vp); -} - -static void SC_updateSimpleMesh(RsSimpleMesh mesh) -{ - GET_TLS(); - SimpleMesh *sm = static_cast<SimpleMesh *>(mesh); - sm->uploadAll(rsc); -} - -static uint32_t SC_loadU32(uint32_t bank, uint32_t offset) -{ - GET_TLS(); - const void *vp = sc->mSlots[bank]->getPtr(); - const uint32_t *i = static_cast<const uint32_t *>(vp); - return i[offset]; -} - -static void SC_loadVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v) -{ - GET_TLS(); - const void *vp = sc->mSlots[bank]->getPtr(); - const float *f = static_cast<const float *>(vp); - memcpy(v, &f[offset], sizeof(rsc_Vector4)); -} - -static void SC_loadMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m) -{ - GET_TLS(); - const void *vp = sc->mSlots[bank]->getPtr(); - const float *f = static_cast<const float *>(vp); - memcpy(m, &f[offset], sizeof(rsc_Matrix)); -} - - -static void SC_storeF(uint32_t bank, uint32_t offset, float v) -{ - //LOGE("storeF %i %i %f", bank, offset, v); - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - float *f = static_cast<float *>(vp); - f[offset] = v; -} - -static void SC_storeI32(uint32_t bank, uint32_t offset, int32_t v) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - int32_t *f = static_cast<int32_t *>(vp); - static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v; -} - -static void SC_storeU32(uint32_t bank, uint32_t offset, uint32_t v) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - uint32_t *f = static_cast<uint32_t *>(vp); - static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v; -} - -static void SC_storeVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - float *f = static_cast<float *>(vp); - memcpy(&f[offset], v, sizeof(rsc_Vector4)); -} - -static void SC_storeMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m) -{ - GET_TLS(); - void *vp = sc->mSlots[bank]->getPtr(); - float *f = static_cast<float *>(vp); - memcpy(&f[offset], m, sizeof(rsc_Matrix)); -} - -////////////////////////////////////////////////////////////////////////////// -// Vec3 routines -////////////////////////////////////////////////////////////////////////////// - -static void SC_vec3Norm(vec3_t *v) -{ - float len = sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); - len = 1 / len; - v->x *= len; - v->y *= len; - v->z *= len; -} - -static float SC_vec3Length(const vec3_t *v) -{ - return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); -} - -static void SC_vec3Add(vec3_t *dest, const vec3_t *lhs, const vec3_t *rhs) -{ - dest->x = lhs->x + rhs->x; - dest->y = lhs->y + rhs->y; - dest->z = lhs->z + rhs->z; -} - -static void SC_vec3Sub(vec3_t *dest, const vec3_t *lhs, const vec3_t *rhs) -{ - dest->x = lhs->x - rhs->x; - dest->y = lhs->y - rhs->y; - dest->z = lhs->z - rhs->z; -} - -static void SC_vec3Cross(vec3_t *dest, const vec3_t *lhs, const vec3_t *rhs) -{ - float x = lhs->y * rhs->z - lhs->z * rhs->y; - float y = lhs->z * rhs->x - lhs->x * rhs->z; - float z = lhs->x * rhs->y - lhs->y * rhs->x; - dest->x = x; - dest->y = y; - dest->z = z; -} - -static float SC_vec3Dot(const vec3_t *lhs, const vec3_t *rhs) -{ - return lhs->x * rhs->x + lhs->y * rhs->y + lhs->z * rhs->z; -} - -static void SC_vec3Scale(vec3_t *lhs, float scale) -{ - lhs->x *= scale; - lhs->y *= scale; - lhs->z *= scale; -} - -////////////////////////////////////////////////////////////////////////////// -// Vec4 routines -////////////////////////////////////////////////////////////////////////////// - -static void SC_vec4Norm(vec4_t *v) -{ - float len = sqrtf(v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w); - len = 1 / len; - v->x *= len; - v->y *= len; - v->z *= len; - v->w *= len; -} - -static float SC_vec4Length(const vec4_t *v) -{ - return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w); -} - -static void SC_vec4Add(vec4_t *dest, const vec4_t *lhs, const vec4_t *rhs) -{ - dest->x = lhs->x + rhs->x; - dest->y = lhs->y + rhs->y; - dest->z = lhs->z + rhs->z; - dest->w = lhs->w + rhs->w; -} - -static void SC_vec4Sub(vec4_t *dest, const vec4_t *lhs, const vec4_t *rhs) -{ - dest->x = lhs->x - rhs->x; - dest->y = lhs->y - rhs->y; - dest->z = lhs->z - rhs->z; - dest->w = lhs->w - rhs->w; -} - -static float SC_vec4Dot(const vec4_t *lhs, const vec4_t *rhs) -{ - return lhs->x * rhs->x + lhs->y * rhs->y + lhs->z * rhs->z + lhs->w * rhs->w; -} - -static void SC_vec4Scale(vec4_t *lhs, float scale) -{ - lhs->x *= scale; - lhs->y *= scale; - lhs->z *= scale; - lhs->w *= scale; -} ////////////////////////////////////////////////////////////////////////////// // Math routines ////////////////////////////////////////////////////////////////////////////// -#define PI 3.1415926f -#define DEG_TO_RAD PI / 180.0f -#define RAD_TO_DEG 180.0f / PI - static float SC_sinf_fast(float x) { const float A = 1.0f / (2.0f * M_PI); @@ -323,6 +73,7 @@ static float SC_cosf_fast(float x) return 0.2215f * (y * fabsf(y) - y) + y; } + static float SC_randf(float max) { float r = (float)rand(); @@ -335,104 +86,20 @@ static float SC_randf2(float min, float max) return r / RAND_MAX * (max - min) + min; } -static int SC_sign(int value) -{ - return (value > 0) - (value < 0); -} - -static float SC_signf(float value) -{ - return (value > 0) - (value < 0); -} - -static float SC_clampf(float amount, float low, float high) -{ - return amount < low ? low : (amount > high ? high : amount); -} - -static int SC_clamp(int amount, int low, int high) -{ - return amount < low ? low : (amount > high ? high : amount); -} - -static float SC_maxf(float a, float b) -{ - return a > b ? a : b; -} - -static float SC_minf(float a, float b) -{ - return a < b ? a : b; -} - -static float SC_sqrf(float v) +static int SC_randi(int max) { - return v * v; + return (int)SC_randf(max); } -static int SC_sqr(int v) +static int SC_randi2(int min, int max) { - return v * v; + return (int)SC_randf2(min, max); } -static float SC_fracf(float v) +static float SC_frac(float v) { - return v - floorf(v); -} - -static float SC_roundf(float v) -{ - return floorf(v + 0.4999999999); -} - -static float SC_distf2(float x1, float y1, float x2, float y2) -{ - float x = x2 - x1; - float y = y2 - y1; - return sqrtf(x * x + y * y); -} - -static float SC_distf3(float x1, float y1, float z1, float x2, float y2, float z2) -{ - float x = x2 - x1; - float y = y2 - y1; - float z = z2 - z1; - return sqrtf(x * x + y * y + z * z); -} - -static float SC_magf2(float a, float b) -{ - return sqrtf(a * a + b * b); -} - -static float SC_magf3(float a, float b, float c) -{ - return sqrtf(a * a + b * b + c * c); -} - -static float SC_radf(float degrees) -{ - return degrees * DEG_TO_RAD; -} - -static float SC_degf(float radians) -{ - return radians * RAD_TO_DEG; -} - -static float SC_lerpf(float start, float stop, float amount) -{ - return start + (stop - start) * amount; -} - -static float SC_normf(float start, float stop, float value) -{ - return (value - start) / (stop - start); -} - -static float SC_mapf(float minStart, float minStop, float maxStart, float maxStop, float value) -{ - return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); + int i = (int)floor(v); + return fmin(v - i, 0x1.fffffep-1f); } ////////////////////////////////////////////////////////////////////////////// @@ -511,880 +178,361 @@ static int32_t SC_year() return timeinfo->tm_year; } -static int32_t SC_uptimeMillis() +static int64_t SC_uptimeMillis() { return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)); } -static int32_t SC_startTimeMillis() +static int64_t SC_uptimeNanos() { - GET_TLS(); - return sc->mEnviroment.mStartTimeMillis; + return systemTime(SYSTEM_TIME_MONOTONIC); } -static int32_t SC_elapsedTimeMillis() +static float SC_getDt() { GET_TLS(); - return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - - sc->mEnviroment.mStartTimeMillis; -} - -////////////////////////////////////////////////////////////////////////////// -// Matrix routines -////////////////////////////////////////////////////////////////////////////// - - -static void SC_matrixLoadIdentity(rsc_Matrix *mat) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->loadIdentity(); -} - -static void SC_matrixLoadFloat(rsc_Matrix *mat, const float *f) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->load(f); -} - -static void SC_matrixLoadMat(rsc_Matrix *mat, const rsc_Matrix *newmat) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->load(reinterpret_cast<const Matrix *>(newmat)); -} - -static void SC_matrixLoadRotate(rsc_Matrix *mat, float rot, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->loadRotate(rot, x, y, z); -} - -static void SC_matrixLoadScale(rsc_Matrix *mat, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->loadScale(x, y, z); -} - -static void SC_matrixLoadTranslate(rsc_Matrix *mat, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->loadTranslate(x, y, z); -} - -static void SC_matrixLoadMultiply(rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->loadMultiply(reinterpret_cast<const Matrix *>(lhs), - reinterpret_cast<const Matrix *>(rhs)); -} - -static void SC_matrixMultiply(rsc_Matrix *mat, const rsc_Matrix *rhs) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->multiply(reinterpret_cast<const Matrix *>(rhs)); -} - -static void SC_matrixRotate(rsc_Matrix *mat, float rot, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->rotate(rot, x, y, z); + int64_t l = sc->mEnviroment.mLastDtTime; + sc->mEnviroment.mLastDtTime = systemTime(SYSTEM_TIME_MONOTONIC); + return ((float)(sc->mEnviroment.mLastDtTime - l)) / 1.0e9; } -static void SC_matrixScale(rsc_Matrix *mat, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->scale(x, y, z); -} - -static void SC_matrixTranslate(rsc_Matrix *mat, float x, float y, float z) -{ - Matrix *m = reinterpret_cast<Matrix *>(mat); - m->translate(x, y, z); -} - - -static void SC_vec2Rand(float *vec, float maxLen) -{ - float angle = SC_randf(PI * 2); - float len = SC_randf(maxLen); - vec[0] = len * sinf(angle); - vec[1] = len * cosf(angle); -} - - ////////////////////////////////////////////////////////////////////////////// -// Context +// ////////////////////////////////////////////////////////////////////////////// -static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va) +static uint32_t SC_allocGetDimX(RsAllocation va) { - GET_TLS(); - rsi_ProgramBindTexture(rsc, - static_cast<ProgramFragment *>(vpf), - slot, - static_cast<Allocation *>(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 void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs) +static uint32_t SC_allocGetDimY(RsAllocation va) { - GET_TLS(); - rsi_ProgramBindSampler(rsc, - static_cast<ProgramFragment *>(vpf), - slot, - static_cast<Sampler *>(vs)); - + const Allocation *a = static_cast<const Allocation *>(va); + CHECK_OBJ(a); + return a->getType()->getDimY(); } -static void SC_bindProgramFragmentStore(RsProgramFragmentStore pfs) +static uint32_t SC_allocGetDimZ(RsAllocation va) { - GET_TLS(); - rsi_ContextBindProgramFragmentStore(rsc, pfs); - + const Allocation *a = static_cast<const Allocation *>(va); + CHECK_OBJ(a); + return a->getType()->getDimZ(); } -static void SC_bindProgramFragment(RsProgramFragment pf) +static uint32_t SC_allocGetDimLOD(RsAllocation va) { - GET_TLS(); - rsi_ContextBindProgramFragment(rsc, pf); - + const Allocation *a = static_cast<const Allocation *>(va); + CHECK_OBJ(a); + return a->getType()->getDimLOD(); } -static void SC_bindProgramVertex(RsProgramVertex pv) +static uint32_t SC_allocGetDimFaces(RsAllocation va) { - GET_TLS(); - rsi_ContextBindProgramVertex(rsc, pv); - + const Allocation *a = static_cast<const Allocation *>(va); + CHECK_OBJ(a); + return a->getType()->getDimFaces(); } -////////////////////////////////////////////////////////////////////////////// -// VP -////////////////////////////////////////////////////////////////////////////// - -static void SC_vpLoadModelMatrix(const rsc_Matrix *m) +static const void * SC_getElementAtX(RsAllocation va, uint32_t x) { - GET_TLS(); - rsc->getVertex()->setModelviewMatrix(m); + 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 void SC_vpLoadTextureMatrix(const rsc_Matrix *m) +static const void * SC_getElementAtXY(RsAllocation va, uint32_t x, uint32_t y) { - GET_TLS(); - rsc->getVertex()->setTextureMatrix(m); + 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())]; } - - -////////////////////////////////////////////////////////////////////////////// -// Drawing -////////////////////////////////////////////////////////////////////////////// - -static void SC_drawLine(float x1, float y1, float z1, - float x2, float y2, float z2) +static const void * SC_getElementAtXYZ(RsAllocation va, uint32_t x, uint32_t y, uint32_t z) { - GET_TLS(); - if (!rsc->setupCheck()) { - return; - } - - float vtx[] = { x1, y1, z1, x2, y2, z2 }; - VertexArray va; - va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx); - if (rsc->checkVersion2_0()) { - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - } else { - va.setupGL(rsc, &rsc->mStateVertexArray); - } - - glDrawArrays(GL_LINES, 0, 2); + 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_drawPoint(float x, float y, float z) -{ - GET_TLS(); - if (!rsc->setupCheck()) { - return; +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(); } - - float vtx[] = { x, y, z }; - - VertexArray va; - va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx); - if (rsc->checkVersion2_0()) { - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - } else { - va.setupGL(rsc, &rsc->mStateVertexArray); - } - - glDrawArrays(GL_POINTS, 0, 1); -} - -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(); - if (!rsc->setupCheck()) { - return; + if (vdst[0]) { + CHECK_OBJ(vdst[0]); + static_cast<ObjectBase *>(vdst[0])->decSysRef(); } - - //LOGE("Quad"); - //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1); - //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2); - //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3); - //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4); - - 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 va; - va.addLegacy(GL_FLOAT, 3, 12, RS_KIND_POSITION, false, (uint32_t)vtx); - va.addLegacy(GL_FLOAT, 2, 8, RS_KIND_TEXTURE, false, (uint32_t)tex); - if (rsc->checkVersion2_0()) { - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - } else { - va.setupGL(rsc, &rsc->mStateVertexArray); + *vdst = vsrc; + //LOGE("SC_setObject *"); +} +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(); } - - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + *vdst = NULL; + //LOGE("SC_clearObject *"); } - -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); +static bool SC_isObject(RsAllocation vsrc) { + return vsrc != NULL; } -static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h) -{ - GET_TLS(); - ObjectBaseRef<const ProgramVertex> tmp(rsc->getVertex()); - rsc->setVertex(rsc->getDefaultProgramVertex()); - //rsc->setupCheck(); - - //GLint crop[4] = {0, h, w, -h}; - float sh = rsc->getHeight(); - SC_drawQuad(x, sh - y, z, - x+w, sh - y, z, - x+w, sh - (y+h), z, - x, sh - (y+h), z); - rsc->setVertex((ProgramVertex *)tmp.get()); +static void SC_debugF(const char *s, float f) { + LOGE("%s %f, 0x%08x", s, f, *((int *) (&f))); } - -static void SC_drawSpriteScreenspaceCropped(float x, float y, float z, float w, float h, - float cx0, float cy0, float cx1, float cy1) -{ - GET_TLS(); - if (!rsc->setupCheck()) { - return; - } - - GLint crop[4] = {cx0, cy0, cx1, cy1}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - glDrawTexfOES(x, y, z, w, h); +static void SC_debugFv2(const char *s, float f1, float f2) { + LOGE("%s {%f, %f}", s, f1, f2); } - -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_debugFv3(const char *s, float f1, float f2, float f3) { + LOGE("%s {%f, %f, %f}", s, f1, f2, f3); } - - -static void SC_drawRect(float x1, float y1, - float x2, float y2, float z) -{ - SC_drawQuad(x1, y2, z, - x2, y2, z, - x2, y1, z, - x1, y1, z); -} - -static void SC_drawSimpleMesh(RsSimpleMesh vsm) -{ - GET_TLS(); - SimpleMesh *sm = static_cast<SimpleMesh *>(vsm); - if (!rsc->setupCheck()) { - return; - } - sm->render(rsc); -} - -static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len) -{ - GET_TLS(); - SimpleMesh *sm = static_cast<SimpleMesh *>(vsm); - if (!rsc->setupCheck()) { - return; - } - sm->renderRange(rsc, start, len); -} - - -////////////////////////////////////////////////////////////////////////////// -// -////////////////////////////////////////////////////////////////////////////// - -static void SC_color(float r, float g, float b, float a) -{ - GET_TLS(); - rsc->mStateVertex.color[0] = r; - rsc->mStateVertex.color[1] = g; - rsc->mStateVertex.color[2] = b; - rsc->mStateVertex.color[3] = a; - if (!rsc->checkVersion2_0()) { - glColor4f(r, g, b, a); - } -} - -static void SC_ambient(float r, float g, float b, float a) -{ - GLfloat params[] = { r, g, b, a }; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, params); -} - -static void SC_diffuse(float r, float g, float b, float a) -{ - GLfloat params[] = { r, g, b, a }; - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params); -} - -static void SC_specular(float r, float g, float b, float a) -{ - GLfloat params[] = { r, g, b, a }; - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, params); +static void SC_debugFv4(const char *s, float f1, float f2, float f3, float f4) { + LOGE("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); } - -static void SC_emission(float r, float g, float b, float a) -{ - GLfloat params[] = { r, g, b, a }; - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params); +static void SC_debugFM4v4(const char *s, const float *f) { + LOGE("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); + LOGE("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); + LOGE("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); + LOGE("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); } - -static void SC_shininess(float s) -{ - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s); +static void SC_debugFM3v3(const char *s, const float *f) { + LOGE("%s {%f, %f, %f", s, f[0], f[3], f[6]); + LOGE("%s %f, %f, %f", s, f[1], f[4], f[7]); + LOGE("%s %f, %f, %f}",s, f[2], f[5], f[8]); } - -static void SC_pointAttenuation(float a, float b, float c) -{ - GLfloat params[] = { a, b, c }; - glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, params); +static void SC_debugFM2v2(const char *s, const float *f) { + LOGE("%s {%f, %f", s, f[0], f[2]); + LOGE("%s %f, %f}",s, f[1], f[3]); } -static void SC_hsbToRgb(float h, float s, float b, float* rgb) -{ - float red = 0.0f; - float green = 0.0f; - float blue = 0.0f; - - float x = h; - float y = s; - float z = b; - - float hf = (x - (int) x) * 6.0f; - int ihf = (int) hf; - float f = hf - ihf; - float pv = z * (1.0f - y); - float qv = z * (1.0f - y * f); - float tv = z * (1.0f - y * (1.0f - f)); - - switch (ihf) { - case 0: // Red is the dominant color - red = z; - green = tv; - blue = pv; - break; - case 1: // Green is the dominant color - red = qv; - green = z; - blue = pv; - break; - case 2: - red = pv; - green = z; - blue = tv; - break; - case 3: // Blue is the dominant color - red = pv; - green = qv; - blue = z; - break; - case 4: - red = tv; - green = pv; - blue = z; - break; - case 5: // Red is the dominant color - red = z; - green = pv; - blue = qv; - break; - } - - rgb[0] = red; - rgb[1] = green; - rgb[2] = blue; +static void SC_debugI32(const char *s, int32_t i) { + LOGE("%s %i 0x%x", s, i, i); } - -static int SC_hsbToAbgr(float h, float s, float b, float a) -{ - float rgb[3]; - SC_hsbToRgb(h, s, b, rgb); - return int(a * 255.0f) << 24 | - int(rgb[2] * 255.0f) << 16 | - int(rgb[1] * 255.0f) << 8 | - int(rgb[0] * 255.0f); +static void SC_debugU32(const char *s, uint32_t i) { + LOGE("%s %i 0x%x", s, i, i); } -static void SC_hsb(float h, float s, float b, float a) -{ - GET_TLS(); - float rgb[3]; - SC_hsbToRgb(h, s, b, rgb); - if (rsc->checkVersion2_0()) { - glVertexAttrib4f(1, rgb[0], rgb[1], rgb[2], a); - } else { - glColor4f(rgb[0], rgb[1], rgb[2], a); - } +static void SC_debugP(const char *s, const void *p) { + LOGE("%s %p", s, p); } -static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel) +static uint32_t SC_toClient2(int cmdID, void *data, int len) { GET_TLS(); - rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel); + //LOGE("SC_toClient %i %i %i", cmdID, len); + return rsc->sendMessageToClient(data, cmdID, len, false); } -static void SC_uploadToBufferObject(RsAllocation va) +static uint32_t SC_toClient(int cmdID) { GET_TLS(); - rsi_AllocationUploadToBufferObject(rsc, va); + //LOGE("SC_toClient %i", cmdID); + return rsc->sendMessageToClient(NULL, cmdID, 0, false); } -static void SC_syncToGL(RsAllocation va) +static uint32_t SC_toClientBlocking2(int cmdID, void *data, int len) { GET_TLS(); - Allocation *a = static_cast<Allocation *>(va); - + //LOGE("SC_toClientBlocking %i %i", cmdID, len); + return rsc->sendMessageToClient(data, cmdID, len, true); } -static void SC_ClearColor(float r, float g, float b, float a) +static uint32_t SC_toClientBlocking(int cmdID) { - //LOGE("c %f %f %f %f", r, g, b, a); GET_TLS(); - sc->mEnviroment.mClearColor[0] = r; - sc->mEnviroment.mClearColor[1] = g; - sc->mEnviroment.mClearColor[2] = b; - sc->mEnviroment.mClearColor[3] = a; + //LOGE("SC_toClientBlocking %i", cmdID); + return rsc->sendMessageToClient(NULL, cmdID, 0, true); } -static void SC_debugF(const char *s, float f) +int SC_divsi3(int a, int b) { - LOGE("%s %f", s, f); + return a / b; } -static void SC_debugHexF(const char *s, float f) -{ - LOGE("%s 0x%x", s, *((int *) (&f))); -} - -static void SC_debugI32(const char *s, int32_t i) -{ - LOGE("%s %i", s, i); -} - -static void SC_debugHexI32(const char *s, int32_t i) -{ - LOGE("%s 0x%x", s, i); -} - -static uint32_t SC_getWidth() -{ - GET_TLS(); - return rsc->getWidth(); -} - -static uint32_t SC_getHeight() +int SC_getAllocation(const void *ptr) { GET_TLS(); - return rsc->getHeight(); -} - -static uint32_t SC_colorFloatRGBAtoUNorm8(float r, float g, float b, float a) -{ - uint32_t c = 0; - c |= (uint32_t)(r * 255.f + 0.5f); - c |= ((uint32_t)(g * 255.f + 0.5f)) << 8; - c |= ((uint32_t)(b * 255.f + 0.5f)) << 16; - c |= ((uint32_t)(a * 255.f + 0.5f)) << 24; - return c; + const Allocation *alloc = sc->ptrToAllocation(ptr); + return (int)alloc; } -static uint32_t SC_colorFloatRGBAto565(float r, float g, float b) +void SC_allocationMarkDirty(RsAllocation a) { - uint32_t ir = (uint32_t)(r * 255.f + 0.5f); - uint32_t ig = (uint32_t)(g * 255.f + 0.5f); - uint32_t ib = (uint32_t)(b * 255.f + 0.5f); - return rs888to565(ir, ig, ib); + Allocation *alloc = static_cast<Allocation *>(a); + alloc->sendDirty(); } -static uint32_t SC_toClient(void *data, int cmdID, int len, int waitForSpace) +void SC_ForEach(RsScript vs, + RsAllocation vin, + RsAllocation vout, + const void *usr) { GET_TLS(); - return rsc->sendMessageToClient(data, cmdID, len, waitForSpace != 0); + 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); } -static void SC_scriptCall(int scriptID) +void SC_ForEach2(RsScript vs, + RsAllocation vin, + RsAllocation vout, + const void *usr, + const RsScriptCall *call) { GET_TLS(); - rsc->runScript((Script *)scriptID, 0); + 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); } - ////////////////////////////////////////////////////////////////////////////// // Class implementation ////////////////////////////////////////////////////////////////////////////// -ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { - // IO - { "loadI32", (void *)&SC_loadI32, - "int", "(int, int)" }, - //{ "loadU32", (void *)&SC_loadU32, "unsigned int", "(int, int)" }, - { "loadF", (void *)&SC_loadF, - "float", "(int, int)" }, - { "loadArrayF", (void *)&SC_loadArrayF, - "float*", "(int, int)" }, - { "loadArrayI32", (void *)&SC_loadArrayI32, - "int*", "(int, int)" }, - { "loadVec4", (void *)&SC_loadVec4, - "void", "(int, int, float *)" }, - { "loadMatrix", (void *)&SC_loadMatrix, - "void", "(int, int, float *)" }, - { "storeI32", (void *)&SC_storeI32, - "void", "(int, int, int)" }, - //{ "storeU32", (void *)&SC_storeU32, "void", "(int, int, unsigned int)" }, - { "storeF", (void *)&SC_storeF, - "void", "(int, int, float)" }, - { "storeVec4", (void *)&SC_storeVec4, - "void", "(int, int, float *)" }, - { "storeMatrix", (void *)&SC_storeMatrix, - "void", "(int, int, float *)" }, - { "loadSimpleMeshVerticesF", (void *)&SC_loadSimpleMeshVerticesF, - "float*", "(int, int)" }, - { "updateSimpleMesh", (void *)&SC_updateSimpleMesh, - "void", "(int)" }, - - // math - { "modf", (void *)&fmod, - "float", "(float, float)" }, - { "abs", (void *)&abs, - "int", "(int)" }, - { "absf", (void *)&fabsf, - "float", "(float)" }, - { "sinf_fast", (void *)&SC_sinf_fast, - "float", "(float)" }, - { "cosf_fast", (void *)&SC_cosf_fast, - "float", "(float)" }, - { "sinf", (void *)&sinf, - "float", "(float)" }, - { "cosf", (void *)&cosf, - "float", "(float)" }, - { "asinf", (void *)&asinf, - "float", "(float)" }, - { "acosf", (void *)&acosf, - "float", "(float)" }, - { "atanf", (void *)&atanf, - "float", "(float)" }, - { "atan2f", (void *)&atan2f, - "float", "(float, float)" }, - { "fabsf", (void *)&fabsf, - "float", "(float)" }, - { "randf", (void *)&SC_randf, - "float", "(float)" }, - { "randf2", (void *)&SC_randf2, - "float", "(float, float)" }, - { "floorf", (void *)&floorf, - "float", "(float)" }, - { "fracf", (void *)&SC_fracf, - "float", "(float)" }, - { "ceilf", (void *)&ceilf, - "float", "(float)" }, - { "roundf", (void *)&SC_roundf, - "float", "(float)" }, - { "expf", (void *)&expf, - "float", "(float)" }, - { "logf", (void *)&logf, - "float", "(float)" }, - { "powf", (void *)&powf, - "float", "(float, float)" }, - { "maxf", (void *)&SC_maxf, - "float", "(float, float)" }, - { "minf", (void *)&SC_minf, - "float", "(float, float)" }, - { "sqrt", (void *)&sqrt, - "int", "(int)" }, - { "sqrtf", (void *)&sqrtf, - "float", "(float)" }, - { "sqr", (void *)&SC_sqr, - "int", "(int)" }, - { "sqrf", (void *)&SC_sqrf, - "float", "(float)" }, - { "sign", (void *)&SC_sign, - "int", "(int)" }, - { "signf", (void *)&SC_signf, - "float", "(float)" }, - { "clamp", (void *)&SC_clamp, - "int", "(int, int, int)" }, - { "clampf", (void *)&SC_clampf, - "float", "(float, float, float)" }, - { "distf2", (void *)&SC_distf2, - "float", "(float, float, float, float)" }, - { "distf3", (void *)&SC_distf3, - "float", "(float, float, float, float, float, float)" }, - { "magf2", (void *)&SC_magf2, - "float", "(float, float)" }, - { "magf3", (void *)&SC_magf3, - "float", "(float, float, float)" }, - { "radf", (void *)&SC_radf, - "float", "(float)" }, - { "degf", (void *)&SC_degf, - "float", "(float)" }, - { "lerpf", (void *)&SC_lerpf, - "float", "(float, float, float)" }, - { "normf", (void *)&SC_normf, - "float", "(float, float, float)" }, - { "mapf", (void *)&SC_mapf, - "float", "(float, float, float, float, float)" }, - { "noisef", (void *)&SC_noisef, - "float", "(float)" }, - { "noisef2", (void *)&SC_noisef2, - "float", "(float, float)" }, - { "noisef3", (void *)&SC_noisef3, - "float", "(float, float, float)" }, - { "turbulencef2", (void *)&SC_turbulencef2, - "float", "(float, float, float)" }, - { "turbulencef3", (void *)&SC_turbulencef3, - "float", "(float, float, float, float)" }, +// 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 }, + + // allocation + { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX }, + { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY }, + { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ }, + { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD }, + { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces }, + { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation }, + + { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX }, + { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY }, + { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ }, + + { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject }, + { "_Z10rsIsObject10rs_element", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject }, + { "_Z10rsIsObject7rs_type", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject }, + { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject }, + { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject }, + { "_Z10rsIsObject9rs_script", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject }, + { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject }, + { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject }, + { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject }, + { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject }, + { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject }, + + { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject }, + { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject }, + { "_Z10rsIsObject7rs_font", (void *)&SC_isObject }, + + + { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty }, + + + // Debug + { "_Z7rsDebugPKcf", (void *)&SC_debugF }, + { "_Z7rsDebugPKcff", (void *)&SC_debugFv2 }, + { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3 }, + { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4 }, + { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4 }, + { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3 }, + { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2 }, + { "_Z7rsDebugPKci", (void *)&SC_debugI32 }, + { "_Z7rsDebugPKcj", (void *)&SC_debugU32 }, + { "_Z7rsDebugPKcPKv", (void *)&SC_debugP }, + + // RS Math + { "_Z6rsRandi", (void *)&SC_randi }, + { "_Z6rsRandii", (void *)&SC_randi2 }, + { "_Z6rsRandf", (void *)&SC_randf }, + { "_Z6rsRandff", (void *)&SC_randf2 }, + { "_Z6rsFracf", (void *)&SC_frac }, // time - { "second", (void *)&SC_second, - "int", "()" }, - { "minute", (void *)&SC_minute, - "int", "()" }, - { "hour", (void *)&SC_hour, - "int", "()" }, - { "day", (void *)&SC_day, - "int", "()" }, - { "month", (void *)&SC_month, - "int", "()" }, - { "year", (void *)&SC_year, - "int", "()" }, - { "uptimeMillis", (void*)&SC_uptimeMillis, - "int", "()" }, // TODO: use long instead - { "startTimeMillis", (void*)&SC_startTimeMillis, - "int", "()" }, // TODO: use long instead - { "elapsedTimeMillis", (void*)&SC_elapsedTimeMillis, - "int", "()" }, // TODO: use long instead - - // matrix - { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity, - "void", "(float *mat)" }, - { "matrixLoadFloat", (void *)&SC_matrixLoadFloat, - "void", "(float *mat, float *f)" }, - { "matrixLoadMat", (void *)&SC_matrixLoadMat, - "void", "(float *mat, float *newmat)" }, - { "matrixLoadRotate", (void *)&SC_matrixLoadRotate, - "void", "(float *mat, float rot, float x, float y, float z)" }, - { "matrixLoadScale", (void *)&SC_matrixLoadScale, - "void", "(float *mat, float x, float y, float z)" }, - { "matrixLoadTranslate", (void *)&SC_matrixLoadTranslate, - "void", "(float *mat, float x, float y, float z)" }, - { "matrixLoadMultiply", (void *)&SC_matrixLoadMultiply, - "void", "(float *mat, float *lhs, float *rhs)" }, - { "matrixMultiply", (void *)&SC_matrixMultiply, - "void", "(float *mat, float *rhs)" }, - { "matrixRotate", (void *)&SC_matrixRotate, - "void", "(float *mat, float rot, float x, float y, float z)" }, - { "matrixScale", (void *)&SC_matrixScale, - "void", "(float *mat, float x, float y, float z)" }, - { "matrixTranslate", (void *)&SC_matrixTranslate, - "void", "(float *mat, float x, float y, float z)" }, - - // vector - { "vec2Rand", (void *)&SC_vec2Rand, - "void", "(float *vec, float maxLen)" }, - - // vec3 - { "vec3Norm", (void *)&SC_vec3Norm, - "void", "(struct vecF32_3_s *)" }, - { "vec3Length", (void *)&SC_vec3Length, - "float", "(struct vecF32_3_s *)" }, - { "vec3Add", (void *)&SC_vec3Add, - "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" }, - { "vec3Sub", (void *)&SC_vec3Sub, - "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" }, - { "vec3Cross", (void *)&SC_vec3Cross, - "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" }, - { "vec3Dot", (void *)&SC_vec3Dot, - "float", "(struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" }, - { "vec3Scale", (void *)&SC_vec3Scale, - "void", "(struct vecF32_3_s *lhs, float scale)" }, - - // vec4 - { "vec4Norm", (void *)&SC_vec4Norm, - "void", "(struct vecF32_4_s *)" }, - { "vec4Length", (void *)&SC_vec4Length, - "float", "(struct vecF32_4_s *)" }, - { "vec4Add", (void *)&SC_vec4Add, - "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" }, - { "vec4Sub", (void *)&SC_vec4Sub, - "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" }, - { "vec4Dot", (void *)&SC_vec4Dot, - "float", "(struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" }, - { "vec4Scale", (void *)&SC_vec4Scale, - "void", "(struct vecF32_4_s *lhs, float scale)" }, - - // context - { "bindProgramFragment", (void *)&SC_bindProgramFragment, - "void", "(int)" }, - { "bindProgramFragmentStore", (void *)&SC_bindProgramFragmentStore, - "void", "(int)" }, - { "bindProgramStore", (void *)&SC_bindProgramFragmentStore, - "void", "(int)" }, - { "bindProgramVertex", (void *)&SC_bindProgramVertex, - "void", "(int)" }, - { "bindSampler", (void *)&SC_bindSampler, - "void", "(int, int, int)" }, - { "bindTexture", (void *)&SC_bindTexture, - "void", "(int, int, int)" }, - - // vp - { "vpLoadModelMatrix", (void *)&SC_vpLoadModelMatrix, - "void", "(void *)" }, - { "vpLoadTextureMatrix", (void *)&SC_vpLoadTextureMatrix, - "void", "(void *)" }, - - - - // drawing - { "drawRect", (void *)&SC_drawRect, - "void", "(float x1, float y1, float x2, float y2, float z)" }, - { "drawQuad", (void *)&SC_drawQuad, - "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" }, - { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords, - "void", "(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)" }, - { "drawSprite", (void *)&SC_drawSprite, - "void", "(float x, float y, float z, float w, float h)" }, - { "drawSpriteScreenspace", (void *)&SC_drawSpriteScreenspace, - "void", "(float x, float y, float z, float w, float h)" }, - { "drawSpriteScreenspaceCropped", (void *)&SC_drawSpriteScreenspaceCropped, - "void", "(float x, float y, float z, float w, float h, float cx0, float cy0, float cx1, float cy1)" }, - { "drawLine", (void *)&SC_drawLine, - "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" }, - { "drawPoint", (void *)&SC_drawPoint, - "void", "(float x1, float y1, float z1)" }, - { "drawSimpleMesh", (void *)&SC_drawSimpleMesh, - "void", "(int ism)" }, - { "drawSimpleMeshRange", (void *)&SC_drawSimpleMeshRange, - "void", "(int ism, int start, int len)" }, - - - // misc - { "pfClearColor", (void *)&SC_ClearColor, - "void", "(float, float, float, float)" }, - { "color", (void *)&SC_color, - "void", "(float, float, float, float)" }, - { "hsb", (void *)&SC_hsb, - "void", "(float, float, float, float)" }, - { "hsbToRgb", (void *)&SC_hsbToRgb, - "void", "(float, float, float, float*)" }, - { "hsbToAbgr", (void *)&SC_hsbToAbgr, - "int", "(float, float, float, float)" }, - { "ambient", (void *)&SC_ambient, - "void", "(float, float, float, float)" }, - { "diffuse", (void *)&SC_diffuse, - "void", "(float, float, float, float)" }, - { "specular", (void *)&SC_specular, - "void", "(float, float, float, float)" }, - { "emission", (void *)&SC_emission, - "void", "(float, float, float, float)" }, - { "shininess", (void *)&SC_shininess, - "void", "(float)" }, - { "pointAttenuation", (void *)&SC_pointAttenuation, - "void", "(float, float, float)" }, - - { "uploadToTexture", (void *)&SC_uploadToTexture, - "void", "(int, int)" }, - { "uploadToBufferObject", (void *)&SC_uploadToBufferObject, - "void", "(int)" }, - - { "syncToGL", (void *)&SC_syncToGL, - "void", "(int)" }, - - { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8, - "int", "(float, float, float, float)" }, - { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565, - "int", "(float, float, float)" }, - - - { "getWidth", (void *)&SC_getWidth, - "int", "()" }, - { "getHeight", (void *)&SC_getHeight, - "int", "()" }, - - { "sendToClient", (void *)&SC_toClient, - "int", "(void *data, int cmdID, int len, int waitForSpace)" }, - - - { "debugF", (void *)&SC_debugF, - "void", "(void *, float)" }, - { "debugI32", (void *)&SC_debugI32, - "void", "(void *, int)" }, - { "debugHexF", (void *)&SC_debugHexF, - "void", "(void *, float)" }, - { "debugHexI32", (void *)&SC_debugHexI32, - "void", "(void *, int)" }, - - { "scriptCall", (void *)&SC_scriptCall, - "void", "(int)" }, - - - { NULL, NULL, NULL, NULL } + { "_Z8rsSecondv", (void *)&SC_second }, + { "_Z8rsMinutev", (void *)&SC_minute }, + { "_Z6rsHourv", (void *)&SC_hour }, + { "_Z5rsDayv", (void *)&SC_day }, + { "_Z7rsMonthv", (void *)&SC_month }, + { "_Z6rsYearv", (void *)&SC_year }, + { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis }, + { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos }, + { "_Z7rsGetDtv", (void*)&SC_getDt }, + + { "_Z14rsSendToClienti", (void *)&SC_toClient }, + { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2 }, + { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking }, + { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2 }, + + { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach }, + //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2 }, + +//////////////////////////////////////////////////////////////////// + + //{ "sinf_fast", (void *)&SC_sinf_fast }, + //{ "cosf_fast", (void *)&SC_cosf_fast }, + + { NULL, NULL } }; const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym) @@ -1400,17 +548,3 @@ const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym) return NULL; } -void ScriptCState::appendDecls(String8 *str) -{ - ScriptCState::SymbolTable_t *syms = gSyms; - while (syms->mPtr) { - str->append(syms->mRet); - str->append(" "); - str->append(syms->mName); - str->append(syms->mParam); - str->append(";\n"); - syms++; - } -} - - diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp new file mode 100644 index 0000000..ce8e7b2 --- /dev/null +++ b/libs/rs/rsScriptC_LibCL.cpp @@ -0,0 +1,314 @@ +/* + * 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" + +// Implements rs_cl.rsh + + +using namespace android; +using namespace android::renderscript; + + +static float SC_acospi(float v) { + return acosf(v)/ M_PI; +} + +static float SC_asinpi(float v) { + return asinf(v) / M_PI; +} + +static float SC_atanpi(float v) { + return atanf(v) / M_PI; +} + +static float SC_atan2pi(float y, float x) { + return atan2f(y, x) / M_PI; +} + +static float SC_cospi(float v) { + return cosf(v * M_PI); +} + +static float SC_exp10(float v) { + return pow(10.f, v); + +} + +static float SC_fract(float v, int *iptr) { + int i = (int)floor(v); + iptr[0] = i; + return fmin(v - i, 0x1.fffffep-1f); +} + +static float SC_log2(float v) { + return log10(v) / log10(2.f); +} + +static float SC_pown(float v, int p) { + return powf(v, (float)p); +} + +static float SC_powr(float v, float p) { + return powf(v, p); +} + +float SC_rootn(float v, int r) { + return pow(v, 1.f / r); +} + +float SC_rsqrt(float v) { + return 1.f / sqrtf(v); +} + +float SC_sincos(float v, float *cosptr) { + *cosptr = cosf(v); + return sinf(v); +} + +static float SC_sinpi(float v) { + return sinf(v * M_PI); +} + +static float SC_tanpi(float v) { + return tanf(v * M_PI); +} + + //{ "logb", (void *)& }, + //{ "mad", (void *)& }, + //{ "nan", (void *)& }, + //{ "tgamma", (void *)& }, + +////////////////////////////////////////////////////////////////////////////// +// Integer +////////////////////////////////////////////////////////////////////////////// + + +static uint32_t SC_abs_i32(int32_t v) {return abs(v);} +static uint16_t SC_abs_i16(int16_t v) {return (uint16_t)abs(v);} +static uint8_t SC_abs_i8(int8_t v) {return (uint8_t)abs(v);} + +static uint32_t SC_clz_u32(uint32_t v) {return __builtin_clz(v);} +static uint16_t SC_clz_u16(uint16_t v) {return (uint16_t)__builtin_clz(v);} +static uint8_t SC_clz_u8(uint8_t v) {return (uint8_t)__builtin_clz(v);} +static int32_t SC_clz_i32(int32_t v) {return (int32_t)__builtin_clz((uint32_t)v);} +static int16_t SC_clz_i16(int16_t v) {return (int16_t)__builtin_clz(v);} +static int8_t SC_clz_i8(int8_t v) {return (int8_t)__builtin_clz(v);} + +static uint32_t SC_max_u32(uint32_t v, uint32_t v2) {return rsMax(v, v2);} +static uint16_t SC_max_u16(uint16_t v, uint16_t v2) {return rsMax(v, v2);} +static uint8_t SC_max_u8(uint8_t v, uint8_t v2) {return rsMax(v, v2);} +static int32_t SC_max_i32(int32_t v, int32_t v2) {return rsMax(v, v2);} +static int16_t SC_max_i16(int16_t v, int16_t v2) {return rsMax(v, v2);} +static int8_t SC_max_i8(int8_t v, int8_t v2) {return rsMax(v, v2);} + +static uint32_t SC_min_u32(uint32_t v, uint32_t v2) {return rsMin(v, v2);} +static uint16_t SC_min_u16(uint16_t v, uint16_t v2) {return rsMin(v, v2);} +static uint8_t SC_min_u8(uint8_t v, uint8_t v2) {return rsMin(v, v2);} +static int32_t SC_min_i32(int32_t v, int32_t v2) {return rsMin(v, v2);} +static int16_t SC_min_i16(int16_t v, int16_t v2) {return rsMin(v, v2);} +static int8_t SC_min_i8(int8_t v, int8_t v2) {return rsMin(v, v2);} + +////////////////////////////////////////////////////////////////////////////// +// Float util +////////////////////////////////////////////////////////////////////////////// + +static float SC_clamp_f32(float amount, float low, float high) +{ + return amount < low ? low : (amount > high ? high : amount); +} + +static float SC_degrees(float radians) +{ + return radians * (180.f / M_PI); +} + +static float SC_max_f32(float v, float v2) +{ + return rsMax(v, v2); +} + +static float SC_min_f32(float v, float v2) +{ + return rsMin(v, v2); +} + +static float SC_mix_f32(float start, float stop, float amount) +{ + //LOGE("lerpf %f %f %f", start, stop, amount); + return start + (stop - start) * amount; +} + +static float SC_radians(float degrees) +{ + return degrees * (M_PI / 180.f); +} + +static float SC_step_f32(float edge, float v) +{ + if (v < edge) return 0.f; + return 1.f; +} + +static float SC_sign_f32(float value) +{ + if (value > 0) return 1.f; + if (value < 0) return -1.f; + return value; +} + + + + + +////////////////////////////////////////////////////////////////////////////// +// 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[] = { + // OpenCL math + { "_Z4acosf", (void *)&acosf }, + { "_Z5acoshf", (void *)&acoshf }, + { "_Z6acospif", (void *)&SC_acospi }, + { "_Z4asinf", (void *)&asinf }, + { "_Z5asinhf", (void *)&asinhf }, + { "_Z6asinpif", (void *)&SC_asinpi }, + { "_Z4atanf", (void *)&atanf }, + { "_Z5atan2f", (void *)&atan2f }, + { "_Z6atanpif", (void *)&SC_atanpi }, + { "_Z7atan2pif", (void *)&SC_atan2pi }, + { "_Z4cbrtf", (void *)&cbrtf }, + { "_Z4ceilf", (void *)&ceilf }, + { "_Z8copysignff", (void *)©signf }, + { "_Z3cosf", (void *)&cosf }, + { "_Z4coshf", (void *)&coshf }, + { "_Z5cospif", (void *)&SC_cospi }, + { "_Z4erfcf", (void *)&erfcf }, + { "_Z3erff", (void *)&erff }, + { "_Z3expf", (void *)&expf }, + { "_Z4exp2f", (void *)&exp2f }, + { "_Z5exp10f", (void *)&SC_exp10 }, + { "_Z5expm1f", (void *)&expm1f }, + { "_Z4fabsf", (void *)&fabsf }, + { "_Z4fdimff", (void *)&fdimf }, + { "_Z5floorf", (void *)&floorf }, + { "_Z3fmafff", (void *)&fmaf }, + { "_Z4fmaxff", (void *)&fmaxf }, + { "_Z4fminff", (void *)&fminf }, // float fmin(float, float) + { "_Z4fmodff", (void *)&fmodf }, + { "_Z5fractfPf", (void *)&SC_fract }, + { "_Z5frexpfPi", (void *)&frexpf }, + { "_Z5hypotff", (void *)&hypotf }, + { "_Z5ilogbf", (void *)&ilogbf }, + { "_Z5ldexpfi", (void *)&ldexpf }, + { "_Z6lgammaf", (void *)&lgammaf }, + { "_Z3logf", (void *)&logf }, + { "_Z4log2f", (void *)&SC_log2 }, + { "_Z5log10f", (void *)&log10f }, + { "_Z5log1pf", (void *)&log1pf }, + //{ "logb", (void *)& }, + //{ "mad", (void *)& }, + { "modf", (void *)&modff }, + //{ "nan", (void *)& }, + { "_Z9nextafterff", (void *)&nextafterf }, + { "_Z3powff", (void *)&powf }, + { "_Z4pownfi", (void *)&SC_pown }, + { "_Z4powrff", (void *)&SC_powr }, + { "_Z9remainderff", (void *)&remainderf }, + { "remquo", (void *)&remquof }, + { "_Z4rintf", (void *)&rintf }, + { "_Z5rootnfi", (void *)&SC_rootn }, + { "_Z5roundf", (void *)&roundf }, + { "_Z5rsqrtf", (void *)&SC_rsqrt }, + { "_Z3sinf", (void *)&sinf }, + { "sincos", (void *)&SC_sincos }, + { "_Z4sinhf", (void *)&sinhf }, + { "_Z5sinpif", (void *)&SC_sinpi }, + { "_Z4sqrtf", (void *)&sqrtf }, + { "_Z3tanf", (void *)&tanf }, + { "_Z4tanhf", (void *)&tanhf }, + { "_Z5tanpif", (void *)&SC_tanpi }, + //{ "tgamma", (void *)& }, + { "_Z5truncf", (void *)&truncf }, + + // OpenCL Int + { "_Z3absi", (void *)&SC_abs_i32 }, + { "_Z3abss", (void *)&SC_abs_i16 }, + { "_Z3absc", (void *)&SC_abs_i8 }, + { "_Z3clzj", (void *)&SC_clz_u32 }, + { "_Z3clzt", (void *)&SC_clz_u16 }, + { "_Z3clzh", (void *)&SC_clz_u8 }, + { "_Z3clzi", (void *)&SC_clz_i32 }, + { "_Z3clzs", (void *)&SC_clz_i16 }, + { "_Z3clzc", (void *)&SC_clz_i8 }, + { "_Z3maxjj", (void *)&SC_max_u32 }, + { "_Z3maxtt", (void *)&SC_max_u16 }, + { "_Z3maxhh", (void *)&SC_max_u8 }, + { "_Z3maxii", (void *)&SC_max_i32 }, + { "_Z3maxss", (void *)&SC_max_i16 }, + { "_Z3maxcc", (void *)&SC_max_i8 }, + { "_Z3minjj", (void *)&SC_min_u32 }, + { "_Z3mintt", (void *)&SC_min_u16 }, + { "_Z3minhh", (void *)&SC_min_u8 }, + { "_Z3minii", (void *)&SC_min_i32 }, + { "_Z3minss", (void *)&SC_min_i16 }, + { "_Z3mincc", (void *)&SC_min_i8 }, + + // OpenCL 6.11.4 + { "_Z5clampfff", (void *)&SC_clamp_f32 }, + { "_Z7degreesf", (void *)&SC_degrees }, + { "_Z3maxff", (void *)&SC_max_f32 }, + { "_Z3minff", (void *)&SC_min_f32 }, + { "_Z3mixfff", (void *)&SC_mix_f32 }, + { "_Z7radiansf", (void *)&SC_radians }, + { "_Z4stepff", (void *)&SC_step_f32 }, + //{ "smoothstep", (void *)& }, + { "_Z4signf", (void *)&SC_sign_f32 }, + + { NULL, NULL } +}; + +const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(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 new file mode 100644 index 0000000..b991cab --- /dev/null +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -0,0 +1,505 @@ +/* + * 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 "rsMatrix.h" + +#include "utils/Timers.h" + +#define GL_GLEXT_PROTOTYPES + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <time.h> + +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 + + +////////////////////////////////////////////////////////////////////////////// +// 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)); + +} + +static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs) +{ + CHECK_OBJ_OR_NULL(vs); + CHECK_OBJ(vpf); + GET_TLS(); + rsi_ProgramBindSampler(rsc, + static_cast<ProgramFragment *>(vpf), + slot, + static_cast<Sampler *>(vs)); + +} + +static void SC_bindProgramStore(RsProgramStore pfs) +{ + CHECK_OBJ_OR_NULL(pfs); + GET_TLS(); + rsi_ContextBindProgramStore(rsc, pfs); +} + +static void SC_bindProgramFragment(RsProgramFragment pf) +{ + CHECK_OBJ_OR_NULL(pf); + GET_TLS(); + rsi_ContextBindProgramFragment(rsc, pf); +} + +static void SC_bindProgramVertex(RsProgramVertex pv) +{ + CHECK_OBJ_OR_NULL(pv); + GET_TLS(); + rsi_ContextBindProgramVertex(rsc, pv); +} + +static void SC_bindProgramRaster(RsProgramRaster pv) +{ + CHECK_OBJ_OR_NULL(pv); + GET_TLS(); + rsi_ContextBindProgramRaster(rsc, pv); +} + +////////////////////////////////////////////////////////////////////////////// +// VP +////////////////////////////////////////////////////////////////////////////// + +static void SC_vpLoadProjectionMatrix(const rsc_Matrix *m) +{ + GET_TLS(); + rsc->getVertex()->setProjectionMatrix(rsc, m); +} + +static void SC_vpLoadModelMatrix(const rsc_Matrix *m) +{ + GET_TLS(); + rsc->getVertex()->setModelviewMatrix(rsc, m); +} + +static void SC_vpLoadTextureMatrix(const rsc_Matrix *m) +{ + GET_TLS(); + rsc->getVertex()->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); + pf->setConstantColor(rsc, r, g, b, a); +} + +static void SC_vpGetProjectionMatrix(rsc_Matrix *m) +{ + GET_TLS(); + rsc->getVertex()->getProjectionMatrix(rsc, 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(); + if (!rsc->setupCheck()) { + return; + } + + //LOGE("Quad"); + //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1); + //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2); + //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3); + //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4); + + 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 va; + va.add(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position"); + va.add(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0"); + va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); + + 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); +} + +static void SC_drawSpriteScreenspace(float x, float y, float z, float w, float h) +{ + GET_TLS(); + ObjectBaseRef<const ProgramVertex> tmp(rsc->getVertex()); + rsc->setVertex(rsc->getDefaultProgramVertex()); + //rsc->setupCheck(); + + //GLint crop[4] = {0, h, w, -h}; + + float sh = rsc->getHeight(); + + SC_drawQuad(x, sh - y, z, + x+w, sh - y, z, + x+w, sh - (y+h), z, + x, sh - (y+h), z); + rsc->setVertex((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) +{ + //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); +} + +static void SC_drawMesh(RsMesh vsm) +{ + CHECK_OBJ(vsm); + GET_TLS(); + Mesh *sm = static_cast<Mesh *>(vsm); + 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); + 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); + 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); + sm->computeBBox(); + *minX = sm->mBBoxMin[0]; + *minY = sm->mBBoxMin[1]; + *minZ = sm->mBBoxMin[2]; + *maxX = sm->mBBoxMax[0]; + *maxY = sm->mBBoxMax[1]; + *maxZ = sm->mBBoxMax[2]; +} + + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + + +static void SC_color(float r, float g, float b, float a) +{ + GET_TLS(); + ProgramFragment *pf = (ProgramFragment *)rsc->getFragment(); + pf->setConstantColor(rsc, r, g, b, a); +} + +static void SC_uploadToTexture2(RsAllocation va, uint32_t baseMipLevel) +{ + CHECK_OBJ(va); + GET_TLS(); + rsi_AllocationUploadToTexture(rsc, va, false, baseMipLevel); +} +static void SC_uploadToTexture(RsAllocation va) +{ + CHECK_OBJ(va); + GET_TLS(); + rsi_AllocationUploadToTexture(rsc, va, false, 0); +} + +static void SC_uploadToBufferObject(RsAllocation va) +{ + CHECK_OBJ(va); + GET_TLS(); + rsi_AllocationUploadToBufferObject(rsc, va); +} + +static void SC_ClearColor(float r, float g, float b, float a) +{ + GET_TLS(); + rsc->setupProgramStore(); + + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); +} + +static void SC_ClearDepth(float v) +{ + GET_TLS(); + rsc->setupProgramStore(); + + glClearDepthf(v); + glClear(GL_DEPTH_BUFFER_BIT); +} + +static uint32_t SC_getWidth() +{ + GET_TLS(); + return rsc->getWidth(); +} + +static uint32_t SC_getHeight() +{ + GET_TLS(); + 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(); + rsc->mStateFont.renderText(text, allocSize, x, y); +} + +static void SC_DrawText(const char *text, int x, int y) +{ + GET_TLS(); + 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) +{ + if(left) { + *left = metrics->left; + } + if(right) { + *right = metrics->right; + } + if(top) { + *top = metrics->top; + } + if(bottom) { + *bottom = metrics->bottom; + } +} + +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(); + Font::Rect metrics; + rsc->mStateFont.measureText(text, textLen, &metrics); + SC_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(); + size_t textLen = strlen(text); + Font::Rect metrics; + rsc->mStateFont.measureText(text, textLen, &metrics); + SC_setMetrics(&metrics, left, right, top, bottom); +} + +static void SC_BindFont(RsFont font) +{ + CHECK_OBJ(font); + GET_TLS(); + rsi_ContextBindFont(rsc, font); +} + +static void SC_FontColor(float r, float g, float b, float a) +{ + GET_TLS(); + 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 }, + { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore }, + { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex }, + { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster }, + { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler }, + { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture }, + + { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix }, + { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix }, + { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix }, + + { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix }, + + { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor }, + + { "_Z11rsgGetWidthv", (void *)&SC_getWidth }, + { "_Z12rsgGetHeightv", (void *)&SC_getHeight }, + + { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2 }, + { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture }, + { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject }, + + { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect }, + { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad }, + { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords }, + { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace }, + + { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh }, + { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive }, + { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange }, + { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox }, + + { "_Z13rsgClearColorffff", (void *)&SC_ClearColor }, + { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth }, + + { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText }, + { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc }, + { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText }, + { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc }, + + { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont }, + { "_Z12rsgFontColorffff", (void *)&SC_FontColor }, + + // misc + { "_Z5colorffff", (void *)&SC_color }, + + { NULL, NULL } +}; + +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/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp index 4711d1b..45f6207 100644 --- a/libs/rs/rsShaderCache.cpp +++ b/libs/rs/rsShaderCache.cpp @@ -14,10 +14,14 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" - #include <GLES/gl.h> #include <GLES2/gl2.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#endif //ANDROID_RS_BUILD_FOR_HOST using namespace android; using namespace android::renderscript; @@ -25,20 +29,15 @@ using namespace android::renderscript; ShaderCache::ShaderCache() { - mEntryCount = 0; - mEntryAllocationCount = 16; - mEntries = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t)); + mEntries.setCapacity(16); } ShaderCache::~ShaderCache() { - for (uint32_t ct=0; ct < mEntryCount; ct++) { - glDeleteProgram(mEntries[ct].program); + for (uint32_t ct=0; ct < mEntries.size(); ct++) { + glDeleteProgram(mEntries[ct]->program); + free(mEntries[ct]); } - - mEntryCount = 0; - mEntryAllocationCount = 0; - free(mEntries); } bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) @@ -49,61 +48,46 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag if (!frag->getShaderID()) { frag->loadShader(rsc); } - //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID()); - for (uint32_t ct=0; ct < mEntryCount; ct++) { - if ((mEntries[ct].vtx == vtx->getShaderID()) && - (mEntries[ct].frag == frag->getShaderID())) { - - //LOGV("SC using program %i", mEntries[ct].program); - glUseProgram(mEntries[ct].program); - mCurrent = &mEntries[ct]; + // Don't try to cache if shaders failed to load + if(!vtx->getShaderID() || !frag->getShaderID()) { + return false; + } + //LOGV("ShaderCache 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()) && + (mEntries[ct]->frag == frag->getShaderID())) { + + //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)"); return true; } } - // Not in cache, add it. - - if (mEntryAllocationCount == mEntryCount) { - // Out of space, make some. - mEntryAllocationCount *= 2; - entry_t *e = (entry_t *)calloc(mEntryAllocationCount, sizeof(entry_t)); - if (!e) { - LOGE("Out of memory for ShaderCache::lookup"); - return false; - } - memcpy(e, mEntries, sizeof(entry_t) * mEntryCount); - free(mEntries); - mEntries = e; - } - //LOGV("ShaderCache miss, using %i", mEntryCount); + //LOGV("ShaderCache miss"); //LOGE("e0 %x", glGetError()); - - entry_t *e = &mEntries[mEntryCount]; + entry_t *e = (entry_t *)malloc(sizeof(entry_t)); + mEntries.push(e); mCurrent = e; e->vtx = vtx->getShaderID(); e->frag = frag->getShaderID(); e->program = glCreateProgram(); - e->mUserVertexProgram = vtx->isUserProgram(); - if (mEntries[mEntryCount].program) { + e->vtxAttrCount = vtx->getAttribCount(); + if (e->program) { GLuint pgm = e->program; glAttachShader(pgm, vtx->getShaderID()); //LOGE("e1 %x", glGetError()); glAttachShader(pgm, frag->getShaderID()); if (!vtx->isUserProgram()) { - glBindAttribLocation(pgm, 0, "ATTRIB_LegacyPosition"); - glBindAttribLocation(pgm, 1, "ATTRIB_LegacyColor"); - glBindAttribLocation(pgm, 2, "ATTRIB_LegacyNormal"); - glBindAttribLocation(pgm, 3, "ATTRIB_LegacyPointSize"); - glBindAttribLocation(pgm, 4, "ATTRIB_LegacyTexture"); - e->mVtxAttribSlots[RS_KIND_POSITION] = 0; - e->mVtxAttribSlots[RS_KIND_COLOR] = 1; - e->mVtxAttribSlots[RS_KIND_NORMAL] = 2; - e->mVtxAttribSlots[RS_KIND_POINT_SIZE] = 3; - e->mVtxAttribSlots[RS_KIND_TEXTURE] = 4; + glBindAttribLocation(pgm, 0, "ATTRIB_position"); + glBindAttribLocation(pgm, 1, "ATTRIB_color"); + glBindAttribLocation(pgm, 2, "ATTRIB_normal"); + glBindAttribLocation(pgm, 3, "ATTRIB_texture0"); } //LOGE("e2 %x", glGetError()); @@ -126,14 +110,15 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag rsc->setError(RS_ERROR_BAD_SHADER, "Error linking GL Programs"); return false; } - if (vtx->isUserProgram()) { - for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) { - e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct)); - if (rsc->props.mLogShaders) { - LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]); - } + + for (uint32_t ct=0; ct < e->vtxAttrCount; ct++) { + e->mVtxAttribSlots[ct] = glGetAttribLocation(pgm, vtx->getAttribName(ct)); + e->mVtxAttribNames[ct] = vtx->getAttribName(ct).string(); + if (rsc->props.mLogShaders) { + LOGV("vtx A %i, %s = %d\n", ct, vtx->getAttribName(ct).string(), e->mVtxAttribSlots[ct]); } } + for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { e->mVtxUniformSlots[ct] = glGetUniformLocation(pgm, vtx->getUniformName(ct)); if (rsc->props.mLogShaders) { @@ -151,17 +136,47 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag e->mIsValid = true; //LOGV("SC made program %i", e->program); glUseProgram(e->program); - mEntryCount++; rsc->checkError("ShaderCache::lookup (miss)"); return true; } +int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { + for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) { + if(attrName == mCurrent->mVtxAttribNames[ct]) { + return mCurrent->mVtxAttribSlots[ct]; + } + } + return -1; +} + void ShaderCache::cleanupVertex(uint32_t id) { + int32_t numEntries = (int32_t)mEntries.size(); + for(int32_t ct = 0; ct < numEntries; ct ++) { + if (mEntries[ct]->vtx == id) { + glDeleteProgram(mEntries[ct]->program); + + free(mEntries[ct]); + mEntries.removeAt(ct); + numEntries = (int32_t)mEntries.size(); + ct --; + } + } } void ShaderCache::cleanupFragment(uint32_t id) { + int32_t numEntries = (int32_t)mEntries.size(); + for(int32_t ct = 0; ct < numEntries; ct ++) { + if (mEntries[ct]->frag == id) { + glDeleteProgram(mEntries[ct]->program); + + free(mEntries[ct]); + mEntries.removeAt(ct); + numEntries = (int32_t)mEntries.size(); + ct --; + } + } } void ShaderCache::cleanupAll() diff --git a/libs/rs/rsShaderCache.h b/libs/rs/rsShaderCache.h index df99ccc..35ff95b 100644 --- a/libs/rs/rsShaderCache.h +++ b/libs/rs/rsShaderCache.h @@ -40,29 +40,30 @@ public: void cleanupAll(); - int32_t vtxAttribSlot(uint32_t a) const {return mCurrent->mVtxAttribSlots[a];} + int32_t vtxAttribSlot(const String8 &attrName) const; int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->mVtxUniformSlots[a];} int32_t fragAttribSlot(uint32_t a) const {return mCurrent->mFragAttribSlots[a];} int32_t fragUniformSlot(uint32_t a) const {return mCurrent->mFragUniformSlots[a];} - bool isUserVertexProgram() const {return mCurrent->mUserVertexProgram;} protected: typedef struct { uint32_t vtx; uint32_t frag; uint32_t program; + uint32_t vtxAttrCount; + const char* mVtxAttribNames[Program::MAX_ATTRIBS]; int32_t mVtxAttribSlots[Program::MAX_ATTRIBS]; int32_t mVtxUniformSlots[Program::MAX_UNIFORMS]; int32_t mFragAttribSlots[Program::MAX_ATTRIBS]; int32_t mFragUniformSlots[Program::MAX_UNIFORMS]; - bool mUserVertexProgram; bool mIsValid; } entry_t; - entry_t *mEntries; + //entry_t *mEntries; + Vector<entry_t*> mEntries; entry_t *mCurrent; - uint32_t mEntryCount; - uint32_t mEntryAllocationCount; + /*uint32_t mEntryCount; + uint32_t mEntryAllocationCount;*/ }; diff --git a/libs/rs/rsSignal.cpp b/libs/rs/rsSignal.cpp new file mode 100644 index 0000000..9239bfd --- /dev/null +++ b/libs/rs/rsSignal.cpp @@ -0,0 +1,98 @@ +/* + * 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 "rsSignal.h" + +using namespace android; +using namespace android::renderscript; + + +Signal::Signal() +{ + mSet = true; +} + +Signal::~Signal() +{ + pthread_mutex_destroy(&mMutex); + pthread_cond_destroy(&mCondition); +} + +bool Signal::init() +{ + int status = pthread_mutex_init(&mMutex, NULL); + if (status) { + LOGE("LocklessFifo mutex init failure"); + return false; + } + + status = pthread_cond_init(&mCondition, NULL); + if (status) { + LOGE("LocklessFifo condition init failure"); + pthread_mutex_destroy(&mMutex); + return false; + } + + return true; +} + +void Signal::set() +{ + int status; + + status = pthread_mutex_lock(&mMutex); + if (status) { + LOGE("LocklessCommandFifo: error %i locking for set condition.", status); + return; + } + + mSet = true; + + status = pthread_cond_signal(&mCondition); + if (status) { + LOGE("LocklessCommandFifo: error %i on set condition.", status); + } + + status = pthread_mutex_unlock(&mMutex); + if (status) { + LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status); + } +} + +void Signal::wait() +{ + int status; + + status = pthread_mutex_lock(&mMutex); + if (status) { + LOGE("LocklessCommandFifo: error %i locking for condition.", status); + return; + } + + if (!mSet) { + status = pthread_cond_wait(&mCondition, &mMutex); + if (status) { + LOGE("LocklessCommandFifo: error %i waiting on condition.", status); + } + } + mSet = false; + + status = pthread_mutex_unlock(&mMutex); + if (status) { + LOGE("LocklessCommandFifo: error %i unlocking for condition.", status); + } +} + diff --git a/libs/rs/rsFileA3DDecls.h b/libs/rs/rsSignal.h index 2a08bd3..2e760f1 100644 --- a/libs/rs/rsFileA3DDecls.h +++ b/libs/rs/rsSignal.h @@ -14,31 +14,33 @@ * limitations under the License. */ -#ifndef ANDROID_RS_FILE_A3D_DECLS_H -#define ANDROID_RS_FILE_A3D_DECLS_H +#ifndef ANDROID_RS_SIGNAL_H +#define ANDROID_RS_SIGNAL_H -#define A3D_MAGIC_KEY "Android3D_ff" +#include "rsUtils.h" namespace android { namespace renderscript { - enum A3DChunkType { - CHUNK_EMPTY, +class Signal { +public: + Signal(); + ~Signal(); - CHUNK_ELEMENT, - CHUNK_ELEMENT_SOURCE, - CHUNK_VERTICIES, - CHUNK_MESH, - CHUNK_PRIMITIVE, + bool init(); - CHUNK_LAST - }; + void set(); + void wait(); +protected: + bool mSet; + pthread_mutex_t mMutex; + pthread_cond_t mCondition; +}; } } -#endif //ANDROID_RS_FILE_A3D_H - +#endif diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp deleted file mode 100644 index 53ce5cd..0000000 --- a/libs/rs/rsSimpleMesh.cpp +++ /dev/null @@ -1,169 +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 "rsContext.h" - -using namespace android; -using namespace android::renderscript; - -#include <GLES/gl.h> -#include <GLES/glext.h> - -SimpleMesh::SimpleMesh(Context *rsc) : ObjectBase(rsc) -{ - mAllocFile = __FILE__; - mAllocLine = __LINE__; -} - -SimpleMesh::~SimpleMesh() -{ - delete[] mVertexTypes; - delete[] mVertexBuffers; -} - -void SimpleMesh::render(Context *rsc) const -{ - if (mPrimitiveType.get()) { - renderRange(rsc, 0, mPrimitiveType->getDimX()); - return; - } - - if (mIndexType.get()) { - renderRange(rsc, 0, mIndexType->getDimX()); - return; - } - - renderRange(rsc, 0, mVertexTypes[0]->getDimX()); -} - -void SimpleMesh::renderRange(Context *rsc, uint32_t start, uint32_t len) const -{ - if (len < 1) { - return; - } - - rsc->checkError("SimpleMesh::renderRange 1"); - VertexArray va; - if (rsc->checkVersion2_0()) { - for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { - mVertexBuffers[ct]->uploadCheck(rsc); - va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID()); - mVertexTypes[ct]->enableGLVertexBuffer2(&va); - } - va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); - } else { - for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { - mVertexBuffers[ct]->uploadCheck(rsc); - va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID()); - mVertexTypes[ct]->enableGLVertexBuffer(&va); - } - va.setupGL(rsc, 0); - } - - rsc->checkError("SimpleMesh::renderRange 2"); - if (mIndexType.get()) { - mIndexBuffer->uploadCheck(rsc); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); - glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); - } else { - glDrawArrays(mGLPrimitive, start, len); - } - - rsc->checkError("SimpleMesh::renderRange"); -} - -void SimpleMesh::uploadAll(Context *rsc) -{ - for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { - if (mVertexBuffers[ct].get()) { - mVertexBuffers[ct]->deferedUploadToBufferObject(rsc); - } - } - if (mIndexBuffer.get()) { - mIndexBuffer->deferedUploadToBufferObject(rsc); - } - if (mPrimitiveBuffer.get()) { - mPrimitiveBuffer->deferedUploadToBufferObject(rsc); - } - rsc->checkError("SimpleMesh::uploadAll"); -} - - -SimpleMeshContext::SimpleMeshContext() -{ -} - -SimpleMeshContext::~SimpleMeshContext() -{ -} - - -namespace android { -namespace renderscript { - - -RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType) -{ - SimpleMesh *sm = new SimpleMesh(rsc); - sm->incUserRef(); - - sm->mIndexType.set((const Type *)idx); - sm->mPrimitiveType.set((const Type *)prim); - - sm->mVertexTypeCount = vtxCount; - sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount]; - sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount]; - for (uint32_t ct=0; ct < vtxCount; ct++) { - sm->mVertexTypes[ct].set((const Type *)vtx[ct]); - } - - sm->mPrimitive = (RsPrimitive)primType; - switch(sm->mPrimitive) { - case RS_PRIMITIVE_POINT: sm->mGLPrimitive = GL_POINTS; break; - case RS_PRIMITIVE_LINE: sm->mGLPrimitive = GL_LINES; break; - case RS_PRIMITIVE_LINE_STRIP: sm->mGLPrimitive = GL_LINE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE: sm->mGLPrimitive = GL_TRIANGLES; break; - case RS_PRIMITIVE_TRIANGLE_STRIP: sm->mGLPrimitive = GL_TRIANGLE_STRIP; break; - case RS_PRIMITIVE_TRIANGLE_FAN: sm->mGLPrimitive = GL_TRIANGLE_FAN; break; - } - return sm; -} - -void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot) -{ - SimpleMesh *sm = static_cast<SimpleMesh *>(mv); - rsAssert(slot < sm->mVertexTypeCount); - - sm->mVertexBuffers[slot].set((Allocation *)va); -} - -void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va) -{ - SimpleMesh *sm = static_cast<SimpleMesh *>(mv); - sm->mIndexBuffer.set((Allocation *)va); -} - -void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va) -{ - SimpleMesh *sm = static_cast<SimpleMesh *>(mv); - sm->mPrimitiveBuffer.set((Allocation *)va); -} - - - - -}} - diff --git a/libs/rs/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h deleted file mode 100644 index 6defbda..0000000 --- a/libs/rs/rsSimpleMesh.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_RS_SIMPLE_MESH_H -#define ANDROID_RS_SIMPLE_MESH_H - - -#include "RenderScript.h" - -// --------------------------------------------------------------------------- -namespace android { -namespace renderscript { - - -// An element is a group of Components that occupies one cell in a structure. -class SimpleMesh : public ObjectBase -{ -public: - SimpleMesh(Context *); - ~SimpleMesh(); - - ObjectBaseRef<const Type> mIndexType; - ObjectBaseRef<const Type> mPrimitiveType; - ObjectBaseRef<const Type> *mVertexTypes; - uint32_t mVertexTypeCount; - - ObjectBaseRef<Allocation> mIndexBuffer; - ObjectBaseRef<Allocation> mPrimitiveBuffer; - ObjectBaseRef<Allocation> *mVertexBuffers; - - RsPrimitive mPrimitive; - uint32_t mGLPrimitive; - - - void render(Context *) const; - void renderRange(Context *, uint32_t start, uint32_t len) const; - void uploadAll(Context *); - - -protected: -}; - -class SimpleMeshContext -{ -public: - SimpleMeshContext(); - ~SimpleMeshContext(); - - -}; - - -} -} -#endif //ANDROID_RS_SIMPLE_MESH_H - diff --git a/libs/rs/rsStream.cpp b/libs/rs/rsStream.cpp new file mode 100644 index 0000000..68241fa --- /dev/null +++ b/libs/rs/rsStream.cpp @@ -0,0 +1,131 @@ + +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif + +#include "rsStream.h" + +using namespace android; +using namespace android::renderscript; + +IStream::IStream(const uint8_t *buf, bool use64) +{ + mData = buf; + mPos = 0; + mUse64 = use64; +} + +void IStream::loadByteArray(void *dest, size_t numBytes) +{ + memcpy(dest, mData + mPos, numBytes); + mPos += numBytes; +} + +uint64_t IStream::loadOffset() +{ + uint64_t tmp; + if (mUse64) { + mPos = (mPos + 7) & (~7); + tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0]; + mPos += sizeof(uint64_t); + return tmp; + } + return loadU32(); +} + +void IStream::loadString(String8 *s) +{ + uint32_t len = loadU32(); + s->setTo((const char *)&mData[mPos], len); + mPos += len; +} + + +// Output stream implementation + +OStream::OStream(uint64_t len, bool use64) +{ + mData = (uint8_t*)malloc(len); + mLength = len; + mPos = 0; + mUse64 = use64; +} + +OStream::~OStream() +{ + free(mData); +} + +void OStream::addByteArray(const void *src, size_t numBytes) +{ + // We need to potentially grow more than once if the number of byes we write is substantial + while(mPos + numBytes >= mLength) { + growSize(); + } + memcpy(mData + mPos, src, numBytes); + mPos += numBytes; +} + +void OStream::addOffset(uint64_t v) +{ + if (mUse64) { + mPos = (mPos + 7) & (~7); + if(mPos + sizeof(v) >= mLength) { + growSize(); + } + mData[mPos++] = (uint8_t)(v & 0xff); + mData[mPos++] = (uint8_t)((v >> 8) & 0xff); + mData[mPos++] = (uint8_t)((v >> 16) & 0xff); + mData[mPos++] = (uint8_t)((v >> 24) & 0xff); + mData[mPos++] = (uint8_t)((v >> 32) & 0xff); + mData[mPos++] = (uint8_t)((v >> 40) & 0xff); + mData[mPos++] = (uint8_t)((v >> 48) & 0xff); + mData[mPos++] = (uint8_t)((v >> 56) & 0xff); + } + else { + addU32(v); + } +} + +void OStream::addString(String8 *s) +{ + uint32_t len = s->size(); + addU32(len); + if(mPos + len*sizeof(char) >= mLength) { + growSize(); + } + char *stringData = reinterpret_cast<char *>(&mData[mPos]); + for(uint32_t i = 0; i < len; i ++) { + stringData[i] = s->string()[i]; + } + mPos += len*sizeof(char); +} + +void OStream::growSize() +{ + uint8_t *newData = (uint8_t*)malloc(mLength*2); + memcpy(newData, mData, mLength*sizeof(uint8_t)); + mLength = mLength * 2; + free(mData); + mData = newData; +} + + diff --git a/libs/rs/rsStream.h b/libs/rs/rsStream.h new file mode 100644 index 0000000..d401cd1 --- /dev/null +++ b/libs/rs/rsStream.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_STREAM_H +#define ANDROID_RS_STREAM_H + +#include <utils/String8.h> +#include <stdio.h> + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class IStream +{ +public: + IStream(const uint8_t *, bool use64); + + float loadF() { + mPos = (mPos + 3) & (~3); + float tmp = reinterpret_cast<const float *>(&mData[mPos])[0]; + mPos += sizeof(float); + return tmp; + } + int32_t loadI32() { + mPos = (mPos + 3) & (~3); + int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0]; + mPos += sizeof(int32_t); + return tmp; + } + uint32_t loadU32() { + mPos = (mPos + 3) & (~3); + uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0]; + mPos += sizeof(uint32_t); + return tmp; + } + uint16_t loadU16() { + mPos = (mPos + 1) & (~1); + uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0]; + mPos += sizeof(uint16_t); + return tmp; + } + inline uint8_t loadU8() { + uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0]; + mPos += sizeof(uint8_t); + return tmp; + } + void loadByteArray(void *dest, size_t numBytes); + uint64_t loadOffset(); + void loadString(String8 *s); + uint64_t getPos() const { + return mPos; + } + void reset(uint64_t pos) { + mPos = pos; + } + void reset() { + mPos = 0; + } + + const uint8_t * getPtr() const { + return mData; + } +protected: + const uint8_t * mData; + uint64_t mPos; + bool mUse64; +}; + +class OStream +{ +public: + OStream(uint64_t length, bool use64); + ~OStream(); + + void align(uint32_t bytes) { + mPos = (mPos + (bytes - 1)) & (~(bytes - 1)); + if(mPos >= mLength) { + growSize(); + } + } + + void addF(float v) { + uint32_t uintV = *reinterpret_cast<uint32_t*> (&v); + addU32(uintV); + } + void addI32(int32_t v) { + mPos = (mPos + 3) & (~3); + if(mPos + sizeof(v) >= mLength) { + growSize(); + } + mData[mPos++] = (uint8_t)(v & 0xff); + mData[mPos++] = (uint8_t)((v >> 8) & 0xff); + mData[mPos++] = (uint8_t)((v >> 16) & 0xff); + mData[mPos++] = (uint8_t)((v >> 24) & 0xff); + } + void addU32(uint32_t v) { + mPos = (mPos + 3) & (~3); + if(mPos + sizeof(v) >= mLength) { + growSize(); + } + mData[mPos++] = (uint8_t)(v & 0xff); + mData[mPos++] = (uint8_t)((v >> 8) & 0xff); + mData[mPos++] = (uint8_t)((v >> 16) & 0xff); + mData[mPos++] = (uint8_t)((v >> 24) & 0xff); + } + void addU16(uint16_t v) { + mPos = (mPos + 1) & (~1); + if(mPos + sizeof(v) >= mLength) { + growSize(); + } + mData[mPos++] = (uint8_t)(v & 0xff); + mData[mPos++] = (uint8_t)(v >> 8); + } + inline void addU8(uint8_t v) { + if(mPos + 1 >= mLength) { + growSize(); + } + reinterpret_cast<uint8_t *>(&mData[mPos])[0] = v; + mPos ++; + } + void addByteArray(const void *src, size_t numBytes); + void addOffset(uint64_t v); + void addString(String8 *s); + uint64_t getPos() const { + return mPos; + } + void reset(uint64_t pos) { + mPos = pos; + } + void reset() { + mPos = 0; + } + const uint8_t * getPtr() const { + return mData; + } +protected: + void growSize(); + uint8_t * mData; + uint64_t mLength; + uint64_t mPos; + bool mUse64; +}; + + +} // renderscript +} // android +#endif //ANDROID_RS_STREAM_H + + diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp index c09e979..27b1b4f 100644 --- a/libs/rs/rsType.cpp +++ b/libs/rs/rsType.cpp @@ -14,8 +14,13 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" #include <GLES/gl.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#endif using namespace android; using namespace android::renderscript; @@ -26,6 +31,8 @@ Type::Type(Context *rsc) : ObjectBase(rsc) mAllocLine = __LINE__; mLODs = 0; mLODCount = 0; + mAttribs = NULL; + mAttribsSize = 0; clear(); } @@ -39,6 +46,11 @@ Type::~Type() } if (mLODs) { delete [] mLODs; + mLODs = NULL; + } + if(mAttribs) { + delete [] mAttribs; + mAttribs = NULL; } } @@ -84,7 +96,9 @@ void Type::compute() mLODCount = 1; } if (mLODCount != oldLODCount) { - delete [] mLODs; + if(mLODs){ + delete [] mLODs; + } mLODs = new LOD[mLODCount]; } @@ -135,139 +149,81 @@ uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) co return offset; } +bool Type::isValidGLComponent(uint32_t fieldIdx) { + // Do not create attribs for padding + if(mElement->getFieldName(fieldIdx)[0] == '#') { + return false; + } -void Type::makeGLComponents() -{ - uint32_t userNum = 0; - - for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) { - const Component &c = getElement()->getField(ct)->getComponent(); - - switch(c.getKind()) { - case RS_KIND_USER: - mGL.mUser[userNum].size = c.getVectorSize(); - mGL.mUser[userNum].offset = mElement->getFieldOffsetBytes(ct); - mGL.mUser[userNum].type = c.getGLType(); - mGL.mUser[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); - mGL.mUser[userNum].name.setTo(getElement()->getFieldName(ct)); - userNum ++; - break; - - case RS_KIND_POSITION: - rsAssert(mGL.mVtx.size == 0); - mGL.mVtx.size = c.getVectorSize(); - mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct); - mGL.mVtx.type = c.getGLType(); - mGL.mVtx.normalized = false; - mGL.mVtx.name.setTo("Position"); - break; - - case RS_KIND_COLOR: - rsAssert(mGL.mColor.size == 0); - mGL.mColor.size = c.getVectorSize(); - mGL.mColor.offset = mElement->getFieldOffsetBytes(ct); - mGL.mColor.type = c.getGLType(); - mGL.mColor.normalized = c.getType() != RS_TYPE_FLOAT_32; - mGL.mColor.name.setTo("Color"); - break; - - case RS_KIND_NORMAL: - rsAssert(mGL.mNorm.size == 0); - mGL.mNorm.size = c.getVectorSize(); - mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct); - mGL.mNorm.type = c.getGLType(); - mGL.mNorm.normalized = false; - mGL.mNorm.name.setTo("Normal"); - break; - - case RS_KIND_TEXTURE: - rsAssert(mGL.mTex.size == 0); - mGL.mTex.size = c.getVectorSize(); - mGL.mTex.offset = mElement->getFieldOffsetBytes(ct); - mGL.mTex.type = c.getGLType(); - mGL.mTex.normalized = false; - mGL.mTex.name.setTo("Texture"); - break; - - case RS_KIND_POINT_SIZE: - rsAssert(!mGL.mPointSize.size); - mGL.mPointSize.size = c.getVectorSize(); - mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct); - mGL.mPointSize.type = c.getGLType(); - mGL.mPointSize.normalized = false; - mGL.mPointSize.name.setTo("PointSize"); - break; + // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. + // Filter rs types accordingly + RsDataType dt = mElement->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; + } - default: - break; - } + // Now make sure they are not arrays + uint32_t arraySize = mElement->getFieldArraySize(fieldIdx); + if(arraySize != 1) { + return false; } + + return true; } -void Type::enableGLVertexBuffer(VertexArray *va) const +void Type::makeGLComponents() { - // Note: We are only going to enable buffers and never disable them - // here. The reason is more than one Allocation may be used as a vertex - // source. So we cannot disable arrays that may have been in use by - // another allocation. + // Count the number of gl attrs to initialize + mAttribsSize = 0; - uint32_t stride = mElement->getSizeBytes(); - if (mGL.mVtx.size) { - va->addLegacy(mGL.mVtx.type, - mGL.mVtx.size, - stride, - RS_KIND_POSITION, - false, - mGL.mVtx.offset); + for (uint32_t ct=0; ct < mElement->getFieldCount(); ct++) { + if(isValidGLComponent(ct)) { + mAttribsSize ++; + } } - - if (mGL.mNorm.size) { - va->addLegacy(mGL.mNorm.type, - 3, - stride, - RS_KIND_NORMAL, - false, - mGL.mNorm.offset); + if(mAttribs) { + delete [] mAttribs; + mAttribs = NULL; } - - if (mGL.mColor.size) { - va->addLegacy(mGL.mColor.type, - mGL.mColor.size, - stride, - RS_KIND_COLOR, - true, - mGL.mColor.offset); + if(mAttribsSize) { + mAttribs = new VertexArray::Attrib[mAttribsSize]; } - if (mGL.mTex.size) { - va->addLegacy(mGL.mTex.type, - mGL.mTex.size, - stride, - RS_KIND_TEXTURE, - false, - mGL.mTex.offset); - } + uint32_t userNum = 0; + for (uint32_t ct=0; ct < mElement->getFieldCount(); ct++) { + const Component &c = mElement->getField(ct)->getComponent(); - if (mGL.mPointSize.size) { - va->addLegacy(mGL.mPointSize.type, - 1, - stride, - RS_KIND_POINT_SIZE, - false, - mGL.mPointSize.offset); - } + if(!isValidGLComponent(ct)) { + continue; + } + + mAttribs[userNum].size = c.getVectorSize(); + mAttribs[userNum].offset = mElement->getFieldOffsetBytes(ct); + mAttribs[userNum].type = c.getGLType(); + mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); + String8 tmp(RS_SHADER_ATTR); + tmp.append(mElement->getFieldName(ct)); + mAttribs[userNum].name.setTo(tmp.string()); + userNum ++; + } } -void Type::enableGLVertexBuffer2(VertexArray *va) const -{ - // Do legacy buffers - enableGLVertexBuffer(va); +void Type::enableGLVertexBuffer(VertexArray *va) const +{ uint32_t stride = mElement->getSizeBytes(); - for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) { - if (mGL.mUser[ct].size) { - va->addUser(mGL.mUser[ct], stride); + for (uint32_t ct=0; ct < mAttribsSize; ct++) { + // Load up to RS_MAX_ATTRIBS inputs + // TODO: grow vertexarray dynamically + if(ct >= RS_MAX_ATTRIBS) { + LOGE("More GL attributes than we can handle"); + break; + } + if (mAttribs[ct].size) { + va->add(mAttribs[ct], stride); } } } @@ -283,6 +239,57 @@ void Type::dumpLOGV(const char *prefix) const mElement->dumpLOGV(buf); } +void Type::serialize(OStream *stream) const +{ + // Need to identify ourselves + stream->addU32((uint32_t)getClassId()); + + String8 name(getName()); + stream->addString(&name); + + mElement->serialize(stream); + + stream->addU32(mDimX); + stream->addU32(mDimY); + stream->addU32(mDimZ); + + stream->addU8((uint8_t)(mDimLOD ? 1 : 0)); + stream->addU8((uint8_t)(mFaces ? 1 : 0)); +} + +Type *Type::createFromStream(Context *rsc, IStream *stream) +{ + // First make sure we are reading the correct object + RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); + if(classID != RS_A3D_CLASS_ID_TYPE) { + LOGE("type loading skipped due to invalid class id\n"); + return NULL; + } + + String8 name; + stream->loadString(&name); + + Element *elem = Element::createFromStream(rsc, stream); + if(!elem) { + return NULL; + } + + Type *type = new Type(rsc); + type->mDimX = stream->loadU32(); + type->mDimY = stream->loadU32(); + type->mDimZ = stream->loadU32(); + + uint8_t temp = stream->loadU8(); + type->mDimLOD = temp != 0; + + temp = stream->loadU8(); + type->mFaces = temp != 0; + + type->setElement(elem); + + return type; +} + bool Type::getIsNp2() const { uint32_t x = getDimX(); @@ -301,97 +308,154 @@ bool Type::getIsNp2() const return false; } +bool Type::isEqual(const Type *other) const { + if(other == NULL) { + return false; + } + if (other->getElement()->isEqual(getElement()) && + other->getDimX() == mDimX && + other->getDimY() == mDimY && + other->getDimZ() == mDimZ && + other->getDimLOD() == mDimLOD && + other->getDimFaces() == mFaces) { + return true; + } + return false; +} -////////////////////////////////////////////////// -// -namespace android { -namespace renderscript { - -void rsi_TypeBegin(Context *rsc, RsElement vse) +Type * Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const { TypeState * stc = &rsc->mStateType; + for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) { + Type *t = stc->mTypes[ct]; + if (t->getElement() != mElement.get()) continue; + if (t->getDimX() != dimX) continue; + if (t->getDimY() != mDimY) continue; + if (t->getDimZ() != mDimZ) continue; + if (t->getDimLOD() != mDimLOD) continue; + if (t->getDimFaces() != mFaces) continue; + t->incUserRef(); + return t; + } - stc->mX = 0; - stc->mY = 0; - stc->mZ = 0; - stc->mLOD = false; - stc->mFaces = false; - stc->mElement.set(static_cast<const Element *>(vse)); + Type *nt = new Type(rsc); + nt->mElement.set(mElement); + nt->mDimX = dimX; + nt->mDimY = mDimY; + nt->mDimZ = mDimZ; + nt->mDimLOD = mDimLOD; + nt->mFaces = mFaces; + nt->compute(); + return nt; } -void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value) +Type * Type::cloneAndResize2D(Context *rsc, uint32_t dimX, uint32_t dimY) const { TypeState * stc = &rsc->mStateType; - - if (dim < 0) { - //error - return; + for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) { + Type *t = stc->mTypes[ct]; + if (t->getElement() != mElement.get()) continue; + if (t->getDimX() != dimX) continue; + if (t->getDimY() != dimY) continue; + if (t->getDimZ() != mDimZ) continue; + if (t->getDimLOD() != mDimLOD) continue; + if (t->getDimFaces() != mFaces) continue; + t->incUserRef(); + return t; } + Type *nt = new Type(rsc); + nt->mElement.set(mElement); + nt->mDimX = dimX; + nt->mDimY = dimY; + nt->mDimZ = mDimZ; + nt->mDimLOD = mDimLOD; + nt->mFaces = mFaces; + nt->compute(); + return nt; +} - switch (dim) { - case RS_DIMENSION_X: - stc->mX = value; - return; - case RS_DIMENSION_Y: - stc->mY = value; - return; - case RS_DIMENSION_Z: - stc->mZ = value; - return; - case RS_DIMENSION_FACE: - stc->mFaces = (value != 0); - return; - case RS_DIMENSION_LOD: - stc->mLOD = (value != 0); - return; - default: - break; - } +////////////////////////////////////////////////// +// +namespace android { +namespace renderscript { - int32_t arrayNum = dim - RS_DIMENSION_ARRAY_0; - if ((dim < 0) || (dim > RS_DIMENSION_MAX)) { - LOGE("rsTypeAdd: Bad dimension"); - //error - return; - } +void rsi_TypeGetNativeData(Context *rsc, RsType type, uint32_t *typeData, uint32_t typeDataSize) +{ + rsAssert(typeDataSize == 6); + // Pack the data in the follofing way mDimX; mDimY; mDimZ; + // mDimLOD; mDimFaces; mElement; into typeData + Type *t = static_cast<Type *>(type); + + (*typeData++) = t->getDimX(); + (*typeData++) = t->getDimY(); + (*typeData++) = t->getDimZ(); + (*typeData++) = t->getDimLOD(); + (*typeData++) = t->getDimFaces() ? 1 : 0; + (*typeData++) = (uint32_t)t->getElement(); + +} - // todo: implement array support } +} -RsType rsi_TypeCreate(Context *rsc) +void * rsaTypeCreate(RsContext con, RsElement _e, uint32_t dimCount, + const RsDimension *dims, const uint32_t *vals) { + Context *rsc = static_cast<Context *>(con); + Element *e = static_cast<Element *>(_e); TypeState * stc = &rsc->mStateType; + uint32_t dimX = 0; + uint32_t dimY = 0; + uint32_t dimZ = 0; + uint32_t dimLOD = 0; + uint32_t dimFaces = 0; + + for (uint32_t ct=0; ct < dimCount; ct++) { + switch(dims[ct]) { + case RS_DIMENSION_X: dimX = vals[ct]; break; + case RS_DIMENSION_Y: dimY = vals[ct]; break; + case RS_DIMENSION_Z: dimZ = vals[ct]; break; + case RS_DIMENSION_LOD: dimLOD = vals[ct]; break; + case RS_DIMENSION_FACE: dimFaces = vals[ct]; break; + + default: + LOGE("rsaTypeCreate: Bad dimension"); + rsAssert(0); + } + } + + ObjectBase::lockUserRef(); for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) { Type *t = stc->mTypes[ct]; - if (t->getElement() != stc->mElement.get()) continue; - if (t->getDimX() != stc->mX) continue; - if (t->getDimY() != stc->mY) continue; - if (t->getDimZ() != stc->mZ) continue; - if (t->getDimLOD() != stc->mLOD) continue; - if (t->getDimFaces() != stc->mFaces) continue; - t->incUserRef(); + if (t->getElement() != e) continue; + if (t->getDimX() != dimX) continue; + if (t->getDimY() != dimY) continue; + if (t->getDimZ() != dimZ) continue; + if (t->getDimLOD() != dimLOD) continue; + if (t->getDimFaces() != dimFaces) continue; + t->prelockedIncUserRef(); + ObjectBase::unlockUserRef(); return t; } + ObjectBase::unlockUserRef(); Type * st = new Type(rsc); st->incUserRef(); - st->setDimX(stc->mX); - st->setDimY(stc->mY); - st->setDimZ(stc->mZ); - st->setElement(stc->mElement.get()); - st->setDimLOD(stc->mLOD); - st->setDimFaces(stc->mFaces); + st->setDimX(dimX); + st->setDimY(dimY); + st->setDimZ(dimZ); + st->setElement(e); + st->setDimLOD(dimLOD); + st->setDimFaces(dimFaces); st->compute(); - stc->mElement.clear(); + + ObjectBase::lockUserRef(); stc->mTypes.push(st); + ObjectBase::unlockUserRef(); return st; } - -} -} - diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h index c25577c..a0c77ab 100644 --- a/libs/rs/rsType.h +++ b/libs/rs/rsType.h @@ -71,9 +71,16 @@ public: void compute(); void enableGLVertexBuffer(class VertexArray *) const; - void enableGLVertexBuffer2(class VertexArray *) const; void dumpLOGV(const char *prefix) const; + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_TYPE; } + static Type *createFromStream(Context *rsc, IStream *stream); + + bool isEqual(const Type *other) const; + + Type * cloneAndResize1D(Context *rsc, uint32_t dimX) const; + Type * cloneAndResize2D(Context *rsc, uint32_t dimX, uint32_t dimY) const; protected: struct LOD { @@ -112,15 +119,9 @@ protected: LOD *mLODs; uint32_t mLODCount; - struct GLState_t { - VertexArray::Attrib mUser[RS_MAX_ATTRIBS]; - VertexArray::Attrib mVtx; - VertexArray::Attrib mNorm; - VertexArray::Attrib mColor; - VertexArray::Attrib mTex; - VertexArray::Attrib mPointSize; - }; - GLState_t mGL; + VertexArray::Attrib *mAttribs; + uint32_t mAttribsSize; + bool isValidGLComponent(uint32_t fieldIdx); void makeGLComponents(); private: @@ -133,14 +134,6 @@ public: TypeState(); ~TypeState(); - size_t mX; - size_t mY; - size_t mZ; - uint32_t mLOD; - bool mFaces; - ObjectBaseRef<const Element> mElement; - - // Cache of all existing types. Vector<Type *> mTypes; }; diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h index 07f8933..17feb22 100644 --- a/libs/rs/rsUtils.h +++ b/libs/rs/rsUtils.h @@ -19,15 +19,23 @@ #define LOG_NDEBUG 0 #define LOG_TAG "RenderScript" + #include <utils/Log.h> -#include <utils/Vector.h> -#include <utils/KeyedVector.h> + +#include "rsStream.h" + #include <utils/String8.h> +#include <utils/Vector.h> + #include <stdlib.h> #include <pthread.h> #include <time.h> +#include <cutils/atomic.h> +#ifndef ANDROID_RS_BUILD_FOR_HOST #include <EGL/egl.h> +#endif + #include <math.h> #include "RenderScript.h" @@ -41,6 +49,26 @@ namespace renderscript { #define rsAssert(v) while(0) #endif +typedef float rsvF_2 __attribute__ ((vector_size (8))); +typedef float rsvF_4 __attribute__ ((vector_size (16))); +typedef uint8_t rsvU8_4 __attribute__ ((vector_size (4))); + +union float2 { + rsvF_2 v; + float f[2]; +}; + +union float4 { + rsvF_4 v; + float f[4]; +}; + +union uchar4 { + rsvU8_4 v; + uint8_t f[4]; + uint32_t packed; +}; + template<typename T> T rsMin(T in1, T in2) { diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp index 6c2002d..4d50124 100644 --- a/libs/rs/rsVertexArray.cpp +++ b/libs/rs/rsVertexArray.cpp @@ -14,10 +14,15 @@ * limitations under the License. */ +#ifndef ANDROID_RS_BUILD_FOR_HOST #include "rsContext.h" - #include <GLES/gl.h> #include <GLES2/gl2.h> +#else +#include "rsContextHostStub.h" +#include <OpenGL/gl.h> +#endif + using namespace android; using namespace android::renderscript; @@ -39,6 +44,7 @@ void VertexArray::clearAll() mAttribs[ct].clear(); } mActiveBuffer = 0; + mActivePointer = NULL; mCount = 0; } @@ -50,12 +56,12 @@ VertexArray::Attrib::Attrib() void VertexArray::Attrib::set(const Attrib &a) { buffer = a.buffer; + ptr = a.ptr; offset = a.offset; type = a.type; size = a.size; stride = a.stride; normalized = a.normalized; - kind = RS_KIND_USER; name.setTo(a.name); } @@ -66,6 +72,7 @@ void VertexArray::Attrib::clear() type = 0; size = 0; stride = 0; + ptr = NULL; normalized = false; name.setTo(""); } @@ -75,138 +82,72 @@ void VertexArray::clear(uint32_t n) mAttribs[n].clear(); } -void VertexArray::addUser(const Attrib &a, uint32_t stride) +void VertexArray::add(const Attrib &a, uint32_t stride) { - assert(mCount < RS_MAX_ATTRIBS); + rsAssert(mCount < RS_MAX_ATTRIBS); mAttribs[mCount].set(a); mAttribs[mCount].buffer = mActiveBuffer; + mAttribs[mCount].ptr = mActivePointer; mAttribs[mCount].stride = stride; - mAttribs[mCount].kind = RS_KIND_USER; mCount ++; } -void VertexArray::addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset) +void VertexArray::add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name) { - assert(mCount < RS_MAX_ATTRIBS); + rsAssert(mCount < RS_MAX_ATTRIBS); mAttribs[mCount].clear(); mAttribs[mCount].type = type; mAttribs[mCount].size = size; mAttribs[mCount].offset = offset; mAttribs[mCount].normalized = normalized; - mAttribs[mCount].buffer = mActiveBuffer; mAttribs[mCount].stride = stride; - mAttribs[mCount].kind = kind; + mAttribs[mCount].name.setTo(name); + + mAttribs[mCount].buffer = mActiveBuffer; + mAttribs[mCount].ptr = mActivePointer; mCount ++; } void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { - LOGE("va %i: slot=%i name=%s buf=%i size=%i type=0x%x kind=%i stride=0x%x norm=%i offset=0x%x", idx, slot, + if(idx == 0) { + LOGV("Starting vertex attribute binding"); + } + LOGV("va %i: slot=%i name=%s buf=%i ptr=%p size=%i type=0x%x stride=0x%x norm=%i offset=0x%x", + idx, slot, mAttribs[idx].name.string(), mAttribs[idx].buffer, + mAttribs[idx].ptr, mAttribs[idx].size, mAttribs[idx].type, - mAttribs[idx].kind, mAttribs[idx].stride, mAttribs[idx].normalized, mAttribs[idx].offset); } -void VertexArray::setupGL(const Context *rsc, class VertexArrayState *state) const -{ - glClientActiveTexture(GL_TEXTURE0); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_POINT_SIZE_ARRAY_OES); - - for (uint32_t ct=0; ct < mCount; ct++) { - switch(mAttribs[ct].kind) { - case RS_KIND_POSITION: - //logAttrib(POSITION); - glEnableClientState(GL_VERTEX_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glVertexPointer(mAttribs[ct].size, - mAttribs[ct].type, - mAttribs[ct].stride, - (void *)mAttribs[ct].offset); - break; - - case RS_KIND_NORMAL: - //logAttrib(NORMAL); - glEnableClientState(GL_NORMAL_ARRAY); - rsAssert(mAttribs[ct].size == 3); - glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glNormalPointer(mAttribs[ct].type, - mAttribs[ct].stride, - (void *)mAttribs[ct].offset); - break; - - case RS_KIND_COLOR: - //logAttrib(COLOR); - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glColorPointer(mAttribs[ct].size, - mAttribs[ct].type, - mAttribs[ct].stride, - (void *)mAttribs[ct].offset); - break; - - case RS_KIND_TEXTURE: - //logAttrib(TEXTURE); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glTexCoordPointer(mAttribs[ct].size, - mAttribs[ct].type, - mAttribs[ct].stride, - (void *)mAttribs[ct].offset); - break; - - case RS_KIND_POINT_SIZE: - //logAttrib(POINT_SIZE); - glEnableClientState(GL_POINT_SIZE_ARRAY_OES); - glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glPointSizePointerOES(mAttribs[ct].type, - mAttribs[ct].stride, - (void *)mAttribs[ct].offset); - break; - - default: - rsAssert(0); - } - } - - rsc->checkError("VertexArray::setupGL"); -} - void VertexArray::setupGL2(const Context *rsc, class VertexArrayState *state, ShaderCache *sc) const { rsc->checkError("VertexArray::setupGL2 start"); - for (uint32_t ct=1; ct <= state->mLastEnableCount; ct++) { + for (uint32_t ct=1; ct <= 0xf/*state->mLastEnableCount*/; ct++) { glDisableVertexAttribArray(ct); } rsc->checkError("VertexArray::setupGL2 disabled"); for (uint32_t ct=0; ct < mCount; ct++) { - uint32_t slot = 0; - if (sc->isUserVertexProgram()) { - slot = sc->vtxAttribSlot(ct); - } else { - if (mAttribs[ct].kind == RS_KIND_USER) { - continue; - } - slot = sc->vtxAttribSlot(mAttribs[ct].kind); + int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name); + if(rsc->props.mLogShadersAttr) { + logAttrib(ct, slot); + } + if(slot < 0) { + continue; } - - //logAttrib(ct, slot); glEnableVertexAttribArray(slot); glBindBuffer(GL_ARRAY_BUFFER, mAttribs[ct].buffer); - glVertexAttribPointer(slot, mAttribs[ct].size, mAttribs[ct].type, mAttribs[ct].normalized, mAttribs[ct].stride, - (void *)mAttribs[ct].offset); + mAttribs[ct].ptr + mAttribs[ct].offset); } state->mLastEnableCount = mCount; rsc->checkError("VertexArray::setupGL2 done"); diff --git a/libs/rs/rsVertexArray.h b/libs/rs/rsVertexArray.h index 3904cb6..dea7d41 100644 --- a/libs/rs/rsVertexArray.h +++ b/libs/rs/rsVertexArray.h @@ -37,13 +37,13 @@ public: class Attrib { public: uint32_t buffer; + const uint8_t * ptr; uint32_t offset; uint32_t type; uint32_t size; uint32_t stride; bool normalized; String8 name; - RsDataKind kind; Attrib(); void set(const Attrib &); @@ -52,17 +52,25 @@ public: void clearAll(); - void setActiveBuffer(uint32_t id) {mActiveBuffer = id;} - void addUser(const Attrib &, uint32_t stride); - void addLegacy(uint32_t type, uint32_t size, uint32_t stride, RsDataKind kind, bool normalized, uint32_t offset); + void setActiveBuffer(uint32_t id) { + mActiveBuffer = id; + mActivePointer = NULL; + } + void setActiveBuffer(const void *ptr) { + mActiveBuffer = 0; + mActivePointer = (const uint8_t *)ptr; + } + + void add(const Attrib &, uint32_t stride); + void add(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name); - void setupGL(const Context *rsc, class VertexArrayState *) const; void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const; void logAttrib(uint32_t idx, uint32_t slot) const; protected: void clear(uint32_t index); uint32_t mActiveBuffer; + const uint8_t * mActivePointer; uint32_t mCount; Attrib mAttribs[RS_MAX_ATTRIBS]; @@ -80,7 +88,7 @@ public: } } -#endif //ANDROID_LIGHT_H +#endif //ANDROID_VERTEX_ARRAY_H diff --git a/libs/rs/rsg_ScriptJavaClass.cpp b/libs/rs/rsg_ScriptJavaClass.cpp index cee9f52..0169b98 100644 --- a/libs/rs/rsg_ScriptJavaClass.cpp +++ b/libs/rs/rsg_ScriptJavaClass.cpp @@ -7,8 +7,12 @@ struct Element; struct ElementField { + // An Element Field is a combination of an Element with a name assigned. + const char *name; Element *e; + + ElementField(const char *n, Element *_e) { name = n; e = _e; @@ -20,12 +24,21 @@ struct ElementField { }; struct Element { + // An Element can take one of two forms. + // 1: Basic. It contains a single basic type and vector size. + // 2: Complex. It contains a list of fields with names. Each field + // will in turn be another element. + ElementField *fields; - size_t fieldCount; + size_t fieldCount; // If field count is 0, the element is a Basic type. const char *name; bool generated; + // The basic data type from RenderScript.h RsDataType compType; + + // The vector size of the data type for float2, float3, .... + // Allowed sizes are 2,3,4,8,16 uint32_t compVectorSize; Element() { diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh new file mode 100644 index 0000000..64844a4 --- /dev/null +++ b/libs/rs/scriptc/rs_cl.rsh @@ -0,0 +1,785 @@ +#ifndef __RS_CL_RSH__ +#define __RS_CL_RSH__ + +#define M_PI 3.14159265358979323846264338327950288f /* pi */ + + +// Conversions +#define CVT_FUNC_2(typeout, typein) \ +static typeout##2 __attribute__((overloadable)) convert_##typeout##2(typein##2 v) { \ + typeout##2 r = {(typeout)v.x, (typeout)v.y}; \ + return r; \ +} \ +static typeout##3 __attribute__((overloadable)) convert_##typeout##3(typein##3 v) { \ + typeout##3 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z}; \ + return r; \ +} \ +static typeout##4 __attribute__((overloadable)) convert_##typeout##4(typein##4 v) { \ + typeout##4 r = {(typeout)v.x, (typeout)v.y, (typeout)v.z, (typeout)v.w}; \ + return r; \ +} + +#define CVT_FUNC(type) CVT_FUNC_2(type, uchar) \ + CVT_FUNC_2(type, char) \ + CVT_FUNC_2(type, ushort) \ + CVT_FUNC_2(type, short) \ + CVT_FUNC_2(type, int) \ + CVT_FUNC_2(type, uint) \ + CVT_FUNC_2(type, float) + +CVT_FUNC(char) +CVT_FUNC(uchar) +CVT_FUNC(short) +CVT_FUNC(ushort) +CVT_FUNC(int) +CVT_FUNC(uint) +CVT_FUNC(float) + + + +// Float ops, 6.11.2 + +#define DEF_FUNC_1(fnc) \ +static float2 __attribute__((overloadable)) fnc(float2 v) { \ + float2 r; \ + r.x = fnc(v.x); \ + r.y = fnc(v.y); \ + return r; \ +} \ +static float3 __attribute__((overloadable)) fnc(float3 v) { \ + float3 r; \ + r.x = fnc(v.x); \ + r.y = fnc(v.y); \ + r.z = fnc(v.z); \ + return r; \ +} \ +static float4 __attribute__((overloadable)) fnc(float4 v) { \ + float4 r; \ + r.x = fnc(v.x); \ + r.y = fnc(v.y); \ + r.z = fnc(v.z); \ + r.w = fnc(v.w); \ + return r; \ +} + +#define DEF_FUNC_2(fnc) \ +static float2 __attribute__((overloadable)) fnc(float2 v1, float2 v2) { \ + float2 r; \ + r.x = fnc(v1.x, v2.x); \ + r.y = fnc(v1.y, v2.y); \ + return r; \ +} \ +static float3 __attribute__((overloadable)) fnc(float3 v1, float3 v2) { \ + float3 r; \ + r.x = fnc(v1.x, v2.x); \ + r.y = fnc(v1.y, v2.y); \ + r.z = fnc(v1.z, v2.z); \ + return r; \ +} \ +static float4 __attribute__((overloadable)) fnc(float4 v1, float4 v2) { \ + float4 r; \ + r.x = fnc(v1.x, v2.x); \ + r.y = fnc(v1.y, v2.y); \ + r.z = fnc(v1.z, v2.z); \ + r.w = fnc(v1.w, v2.z); \ + return r; \ +} + +#define DEF_FUNC_2F(fnc) \ +static float2 __attribute__((overloadable)) fnc(float2 v1, float v2) { \ + float2 r; \ + r.x = fnc(v1.x, v2); \ + r.y = fnc(v1.y, v2); \ + return r; \ +} \ +static float3 __attribute__((overloadable)) fnc(float3 v1, float v2) { \ + float3 r; \ + r.x = fnc(v1.x, v2); \ + r.y = fnc(v1.y, v2); \ + r.z = fnc(v1.z, v2); \ + return r; \ +} \ +static float4 __attribute__((overloadable)) fnc(float4 v1, float v2) { \ + float4 r; \ + r.x = fnc(v1.x, v2); \ + r.y = fnc(v1.y, v2); \ + r.z = fnc(v1.z, v2); \ + r.w = fnc(v1.w, v2); \ + return r; \ +} + + +extern float __attribute__((overloadable)) acos(float); +DEF_FUNC_1(acos) + +extern float __attribute__((overloadable)) acosh(float); +DEF_FUNC_1(acosh) + +static float __attribute__((overloadable)) acospi(float v) { + return acos(v) / M_PI; +} +DEF_FUNC_1(acospi) + +extern float __attribute__((overloadable)) asin(float); +DEF_FUNC_1(asin) + +extern float __attribute__((overloadable)) asinh(float); +DEF_FUNC_1(asinh) + +static float __attribute__((overloadable)) asinpi(float v) { + return asin(v) / M_PI; +} +DEF_FUNC_1(asinpi) + +extern float __attribute__((overloadable)) atan(float); +DEF_FUNC_1(atan) + +extern float __attribute__((overloadable)) atan2(float, float); +DEF_FUNC_2(atan2) + +extern float __attribute__((overloadable)) atanh(float); +DEF_FUNC_1(atanh) + +static float __attribute__((overloadable)) atanpi(float v) { + return atan(v) / M_PI; +} +DEF_FUNC_1(atanpi) + +static float __attribute__((overloadable)) atan2pi(float y, float x) { + return atan2(y, x) / M_PI; +} +DEF_FUNC_2(atan2pi) + +extern float __attribute__((overloadable)) cbrt(float); +DEF_FUNC_1(cbrt) + +extern float __attribute__((overloadable)) ceil(float); +DEF_FUNC_1(ceil) + +extern float __attribute__((overloadable)) copysign(float, float); +DEF_FUNC_2(copysign) + +extern float __attribute__((overloadable)) cos(float); +DEF_FUNC_1(cos) + +extern float __attribute__((overloadable)) cosh(float); +DEF_FUNC_1(cosh) + +static float __attribute__((overloadable)) cospi(float v) { + return cos(v * M_PI); +} +DEF_FUNC_1(cospi) + +extern float __attribute__((overloadable)) erfc(float); +DEF_FUNC_1(erfc) + +extern float __attribute__((overloadable)) erf(float); +DEF_FUNC_1(erf) + +extern float __attribute__((overloadable)) exp(float); +DEF_FUNC_1(exp) + +extern float __attribute__((overloadable)) exp2(float); +DEF_FUNC_1(exp2) + +extern float __attribute__((overloadable)) pow(float, float); +static float __attribute__((overloadable)) exp10(float v) { + return pow(10.f, v); +} +DEF_FUNC_1(exp10) + +extern float __attribute__((overloadable)) expm1(float); +DEF_FUNC_1(expm1) + +extern float __attribute__((overloadable)) fabs(float); +DEF_FUNC_1(fabs) + +extern float __attribute__((overloadable)) fdim(float, float); +DEF_FUNC_2(fdim) + +extern float __attribute__((overloadable)) floor(float); +DEF_FUNC_1(floor) + +extern float __attribute__((overloadable)) fma(float, float, float); +extern float2 __attribute__((overloadable)) fma(float2, float2, float2); +extern float3 __attribute__((overloadable)) fma(float3, float3, float3); +extern float4 __attribute__((overloadable)) fma(float4, float4, float4); + +extern float __attribute__((overloadable)) fmax(float, float); +DEF_FUNC_2(fmax); +DEF_FUNC_2F(fmax); + +extern float __attribute__((overloadable)) fmin(float, float); +DEF_FUNC_2(fmin); +DEF_FUNC_2F(fmin); + +extern float __attribute__((overloadable)) fmod(float, float); +DEF_FUNC_2(fmod) + +static float __attribute__((overloadable)) fract(float v, float *iptr) { + int i = (int)floor(v); + iptr[0] = i; + return fmin(v - i, 0x1.fffffep-1f); +} +static float2 __attribute__((overloadable)) fract(float2 v, float2 *iptr) { + float t[2]; + float2 r; + r.x = fract(v.x, &t[0]); + r.y = fract(v.y, &t[1]); + iptr[0] = t[0]; + iptr[1] = t[1]; + return r; +} +static float3 __attribute__((overloadable)) fract(float3 v, float3 *iptr) { + float t[3]; + float3 r; + r.x = fract(v.x, &t[0]); + r.y = fract(v.y, &t[1]); + r.z = fract(v.z, &t[2]); + iptr[0] = t[0]; + iptr[1] = t[1]; + iptr[2] = t[2]; + return r; +} +static float4 __attribute__((overloadable)) fract(float4 v, float4 *iptr) { + float t[4]; + float4 r; + r.x = fract(v.x, &t[0]); + r.y = fract(v.y, &t[1]); + r.z = fract(v.z, &t[2]); + r.w = fract(v.w, &t[3]); + iptr[0] = t[0]; + iptr[1] = t[1]; + iptr[2] = t[2]; + iptr[3] = t[3]; + return r; +} + +extern float __attribute__((overloadable)) frexp(float, float *); +extern float2 __attribute__((overloadable)) frexp(float2, float2 *); +extern float3 __attribute__((overloadable)) frexp(float3, float3 *); +extern float4 __attribute__((overloadable)) frexp(float4, float4 *); + +extern float __attribute__((overloadable)) hypot(float, float); +DEF_FUNC_2(hypot) + +extern int __attribute__((overloadable)) ilogb(float); +DEF_FUNC_1(ilogb) + +extern float __attribute__((overloadable)) ldexp(float, int); +extern float2 __attribute__((overloadable)) ldexp(float2, int2); +extern float3 __attribute__((overloadable)) ldexp(float3, int3); +extern float4 __attribute__((overloadable)) ldexp(float4, int4); +extern float2 __attribute__((overloadable)) ldexp(float2, int); +extern float3 __attribute__((overloadable)) ldexp(float3, int); +extern float4 __attribute__((overloadable)) ldexp(float4, int); + +extern float __attribute__((overloadable)) lgamma(float); +DEF_FUNC_1(lgamma) +extern float __attribute__((overloadable)) lgamma(float, float *); +extern float2 __attribute__((overloadable)) lgamma(float2, float2 *); +extern float3 __attribute__((overloadable)) lgamma(float3, float3 *); +extern float4 __attribute__((overloadable)) lgamma(float4, float4 *); + +extern float __attribute__((overloadable)) log(float); +DEF_FUNC_1(log) + + +extern float __attribute__((overloadable)) log10(float); +DEF_FUNC_1(log10) + +static float __attribute__((overloadable)) log2(float v) { + return log10(v) / log10(2.f); +} +DEF_FUNC_1(log2) + +extern float __attribute__((overloadable)) log1p(float); +DEF_FUNC_1(log1p) + +extern float __attribute__((overloadable)) logb(float); +DEF_FUNC_1(logb) + +extern float __attribute__((overloadable)) mad(float, float, float); +extern float2 __attribute__((overloadable)) mad(float2, float2, float2); +extern float3 __attribute__((overloadable)) mad(float3, float3, float3); +extern float4 __attribute__((overloadable)) mad(float4, float4, float4); + +extern float __attribute__((overloadable)) modf(float, float *); +extern float2 __attribute__((overloadable)) modf(float2, float2 *); +extern float3 __attribute__((overloadable)) modf(float3, float3 *); +extern float4 __attribute__((overloadable)) modf(float4, float4 *); + +//extern float __attribute__((overloadable)) nan(uint); + +extern float __attribute__((overloadable)) nextafter(float, float); +DEF_FUNC_2(nextafter) + +DEF_FUNC_2(pow) + +static float __attribute__((overloadable)) pown(float v, int p) { + return pow(v, (float)p); +} +static float2 __attribute__((overloadable)) pown(float2 v, int2 p) { + return pow(v, (float2)p); +} +static float3 __attribute__((overloadable)) pown(float3 v, int3 p) { + return pow(v, (float3)p); +} +static float4 __attribute__((overloadable)) pown(float4 v, int4 p) { + return pow(v, (float4)p); +} + +static float __attribute__((overloadable)) powr(float v, float p) { + return pow(v, p); +} +static float2 __attribute__((overloadable)) powr(float2 v, float2 p) { + return pow(v, p); +} +static float3 __attribute__((overloadable)) powr(float3 v, float3 p) { + return pow(v, p); +} +static float4 __attribute__((overloadable)) powr(float4 v, float4 p) { + return pow(v, p); +} + +extern float __attribute__((overloadable)) remainder(float, float); +DEF_FUNC_2(remainder) + +extern float __attribute__((overloadable)) remquo(float, float, float *); +extern float2 __attribute__((overloadable)) remquo(float2, float2, float2 *); +extern float3 __attribute__((overloadable)) remquo(float3, float3, float3 *); +extern float4 __attribute__((overloadable)) remquo(float4, float4, float4 *); + +extern float __attribute__((overloadable)) rint(float); +DEF_FUNC_1(rint) + +static float __attribute__((overloadable)) rootn(float v, int r) { + return pow(v, 1.f / r); +} +static float2 __attribute__((overloadable)) rootn(float2 v, int2 r) { + float2 t = {1.f / r.x, 1.f / r.y}; + return pow(v, t); +} +static float3 __attribute__((overloadable)) rootn(float3 v, int3 r) { + float3 t = {1.f / r.x, 1.f / r.y, 1.f / r.z}; + return pow(v, t); +} +static float4 __attribute__((overloadable)) rootn(float4 v, int4 r) { + float4 t = {1.f / r.x, 1.f / r.y, 1.f / r.z, 1.f / r.w}; + return pow(v, t); +} + +extern float __attribute__((overloadable)) round(float); +DEF_FUNC_1(round) + +extern float __attribute__((overloadable)) sqrt(float); +/*static float __attribute__((overloadable)) rsqrt(float v) { + return 1.f / sqrt(v); +} +DEF_FUNC_1(rsqrt)*/ + +extern float __attribute__((overloadable)) sin(float); +DEF_FUNC_1(sin) + +static float __attribute__((overloadable)) sincos(float v, float *cosptr) { + *cosptr = cos(v); + return sin(v); +} +static float2 __attribute__((overloadable)) sincos(float2 v, float2 *cosptr) { + *cosptr = cos(v); + return sin(v); +} +static float3 __attribute__((overloadable)) sincos(float3 v, float3 *cosptr) { + *cosptr = cos(v); + return sin(v); +} +static float4 __attribute__((overloadable)) sincos(float4 v, float4 *cosptr) { + *cosptr = cos(v); + return sin(v); +} + +extern float __attribute__((overloadable)) sinh(float); +DEF_FUNC_1(sinh) + +static float __attribute__((overloadable)) sinpi(float v) { + return sin(v * M_PI); +} +DEF_FUNC_1(sinpi) + +DEF_FUNC_1(sqrt) + +extern float __attribute__((overloadable)) tan(float); +DEF_FUNC_1(tan) + +extern float __attribute__((overloadable)) tanh(float); +DEF_FUNC_1(tanh) + +static float __attribute__((overloadable)) tanpi(float v) { + return tan(v * M_PI); +} +DEF_FUNC_1(tanpi) + +extern float __attribute__((overloadable)) tgamma(float); +DEF_FUNC_1(tgamma) + +extern float __attribute__((overloadable)) trunc(float); +DEF_FUNC_1(trunc) + +// Int ops (partial), 6.11.3 +extern uint __attribute__((overloadable)) abs(int); +extern ushort __attribute__((overloadable)) abs(short); +extern uchar __attribute__((overloadable)) abs(char); + +extern uint __attribute__((overloadable)) clz(uint); +extern int __attribute__((overloadable)) clz(int); +extern ushort __attribute__((overloadable)) clz(ushort); +extern short __attribute__((overloadable)) clz(short); +extern uchar __attribute__((overloadable)) clz(uchar); +extern char __attribute__((overloadable)) clz(char); + +static uint __attribute__((overloadable)) min(uint v1, uint v2) { + return v1 < v2 ? v1 : v2; +} +static int __attribute__((overloadable)) min(int v1, int v2) { + return v1 < v2 ? v1 : v2; +} +static ushort __attribute__((overloadable)) min(ushort v1, ushort v2) { + return v1 < v2 ? v1 : v2; +} +static short __attribute__((overloadable)) min(short v1, short v2) { + return v1 < v2 ? v1 : v2; +} +static uchar __attribute__((overloadable)) min(uchar v1, uchar v2) { + return v1 < v2 ? v1 : v2; +} +static char __attribute__((overloadable)) min(char v1, char v2) { + return v1 < v2 ? v1 : v2; +} + +static uint __attribute__((overloadable)) max(uint v1, uint v2) { + return v1 > v2 ? v1 : v2; +} +static int __attribute__((overloadable)) max(int v1, int v2) { + return v1 > v2 ? v1 : v2; +} +static ushort __attribute__((overloadable)) max(ushort v1, ushort v2) { + return v1 > v2 ? v1 : v2; +} +static short __attribute__((overloadable)) max(short v1, short v2) { + return v1 > v2 ? v1 : v2; +} +static uchar __attribute__((overloadable)) max(uchar v1, uchar v2) { + return v1 > v2 ? v1 : v2; +} +static char __attribute__((overloadable)) max(char v1, char v2) { + return v1 > v2 ? v1 : v2; +} + + + + +// 6.11.4 + +static float __attribute__((overloadable)) clamp(float amount, float low, float high) { + return amount < low ? low : (amount > high ? high : amount); +} +static float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high) { + float2 r; + r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); + r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); + return r; +} +static float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high) { + float3 r; + r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); + r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); + r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z); + return r; +} +static float4 __attribute__((overloadable)) clamp(float4 amount, float4 low, float4 high) { + float4 r; + r.x = amount.x < low.x ? low.x : (amount.x > high.x ? high.x : amount.x); + r.y = amount.y < low.y ? low.y : (amount.y > high.y ? high.y : amount.y); + r.z = amount.z < low.z ? low.z : (amount.z > high.z ? high.z : amount.z); + r.w = amount.w < low.w ? low.w : (amount.w > high.w ? high.w : amount.w); + return r; +} +static float2 __attribute__((overloadable)) clamp(float2 amount, float low, float high) { + float2 r; + r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); + r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); + return r; +} +static float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high) { + float3 r; + r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); + r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); + r.z = amount.z < low ? low : (amount.z > high ? high : amount.z); + return r; +} +static float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high) { + float4 r; + r.x = amount.x < low ? low : (amount.x > high ? high : amount.x); + r.y = amount.y < low ? low : (amount.y > high ? high : amount.y); + r.z = amount.z < low ? low : (amount.z > high ? high : amount.z); + r.w = amount.w < low ? low : (amount.w > high ? high : amount.w); + return r; +} + +static float __attribute__((overloadable)) degrees(float radians) { + return radians * (180.f / M_PI); +} +DEF_FUNC_1(degrees) + +static float __attribute__((overloadable)) max(float v1, float v2) { + return v1 > v2 ? v1 : v2; +} +static float2 __attribute__((overloadable)) max(float2 v1, float2 v2) { + float2 r; + r.x = v1.x > v2.x ? v1.x : v2.x; + r.y = v1.y > v2.y ? v1.y : v2.y; + return r; +} +static float3 __attribute__((overloadable)) max(float3 v1, float3 v2) { + float3 r; + r.x = v1.x > v2.x ? v1.x : v2.x; + r.y = v1.y > v2.y ? v1.y : v2.y; + r.z = v1.z > v2.z ? v1.z : v2.z; + return r; +} +static float4 __attribute__((overloadable)) max(float4 v1, float4 v2) { + float4 r; + r.x = v1.x > v2.x ? v1.x : v2.x; + r.y = v1.y > v2.y ? v1.y : v2.y; + r.z = v1.z > v2.z ? v1.z : v2.z; + r.w = v1.w > v2.w ? v1.w : v2.w; + return r; +} +static float2 __attribute__((overloadable)) max(float2 v1, float v2) { + float2 r; + r.x = v1.x > v2 ? v1.x : v2; + r.y = v1.y > v2 ? v1.y : v2; + return r; +} +static float3 __attribute__((overloadable)) max(float3 v1, float v2) { + float3 r; + r.x = v1.x > v2 ? v1.x : v2; + r.y = v1.y > v2 ? v1.y : v2; + r.z = v1.z > v2 ? v1.z : v2; + return r; +} +static float4 __attribute__((overloadable)) max(float4 v1, float v2) { + float4 r; + r.x = v1.x > v2 ? v1.x : v2; + r.y = v1.y > v2 ? v1.y : v2; + r.z = v1.z > v2 ? v1.z : v2; + r.w = v1.w > v2 ? v1.w : v2; + return r; +} + +static float __attribute__((overloadable)) min(float v1, float v2) { + return v1 < v2 ? v1 : v2; +} +static float2 __attribute__((overloadable)) min(float2 v1, float2 v2) { + float2 r; + r.x = v1.x < v2.x ? v1.x : v2.x; + r.y = v1.y < v2.y ? v1.y : v2.y; + return r; +} +static float3 __attribute__((overloadable)) min(float3 v1, float3 v2) { + float3 r; + r.x = v1.x < v2.x ? v1.x : v2.x; + r.y = v1.y < v2.y ? v1.y : v2.y; + r.z = v1.z < v2.z ? v1.z : v2.z; + return r; +} +static float4 __attribute__((overloadable)) min(float4 v1, float4 v2) { + float4 r; + r.x = v1.x < v2.x ? v1.x : v2.x; + r.y = v1.y < v2.y ? v1.y : v2.y; + r.z = v1.z < v2.z ? v1.z : v2.z; + r.w = v1.w < v2.w ? v1.w : v2.w; + return r; +} +static float2 __attribute__((overloadable)) min(float2 v1, float v2) { + float2 r; + r.x = v1.x < v2 ? v1.x : v2; + r.y = v1.y < v2 ? v1.y : v2; + return r; +} +static float3 __attribute__((overloadable)) min(float3 v1, float v2) { + float3 r; + r.x = v1.x < v2 ? v1.x : v2; + r.y = v1.y < v2 ? v1.y : v2; + r.z = v1.z < v2 ? v1.z : v2; + return r; +} +static float4 __attribute__((overloadable)) min(float4 v1, float v2) { + float4 r; + r.x = v1.x < v2 ? v1.x : v2; + r.y = v1.y < v2 ? v1.y : v2; + r.z = v1.z < v2 ? v1.z : v2; + r.w = v1.w < v2 ? v1.w : v2; + return r; +} + +static float __attribute__((overloadable)) mix(float start, float stop, float amount) { + return start + (stop - start) * amount; +} +static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount) { + return start + (stop - start) * amount; +} +static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount) { + return start + (stop - start) * amount; +} +static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float4 amount) { + return start + (stop - start) * amount; +} +static float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float amount) { + return start + (stop - start) * amount; +} +static float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount) { + return start + (stop - start) * amount; +} +static float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount) { + return start + (stop - start) * amount; +} + +static float __attribute__((overloadable)) radians(float degrees) { + return degrees * (M_PI / 180.f); +} +DEF_FUNC_1(radians) + +static float __attribute__((overloadable)) step(float edge, float v) { + return (v < edge) ? 0.f : 1.f; +} +static float2 __attribute__((overloadable)) step(float2 edge, float2 v) { + float2 r; + r.x = (v.x < edge.x) ? 0.f : 1.f; + r.y = (v.y < edge.y) ? 0.f : 1.f; + return r; +} +static float3 __attribute__((overloadable)) step(float3 edge, float3 v) { + float3 r; + r.x = (v.x < edge.x) ? 0.f : 1.f; + r.y = (v.y < edge.y) ? 0.f : 1.f; + r.z = (v.z < edge.z) ? 0.f : 1.f; + return r; +} +static float4 __attribute__((overloadable)) step(float4 edge, float4 v) { + float4 r; + r.x = (v.x < edge.x) ? 0.f : 1.f; + r.y = (v.y < edge.y) ? 0.f : 1.f; + r.z = (v.z < edge.z) ? 0.f : 1.f; + r.w = (v.w < edge.w) ? 0.f : 1.f; + return r; +} +static float2 __attribute__((overloadable)) step(float2 edge, float v) { + float2 r; + r.x = (v < edge.x) ? 0.f : 1.f; + r.y = (v < edge.y) ? 0.f : 1.f; + return r; +} +static float3 __attribute__((overloadable)) step(float3 edge, float v) { + float3 r; + r.x = (v < edge.x) ? 0.f : 1.f; + r.y = (v < edge.y) ? 0.f : 1.f; + r.z = (v < edge.z) ? 0.f : 1.f; + return r; +} +static float4 __attribute__((overloadable)) step(float4 edge, float v) { + float4 r; + r.x = (v < edge.x) ? 0.f : 1.f; + r.y = (v < edge.y) ? 0.f : 1.f; + r.z = (v < edge.z) ? 0.f : 1.f; + r.w = (v < edge.w) ? 0.f : 1.f; + return r; +} + +extern float __attribute__((overloadable)) smoothstep(float, float, float); +extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2); +extern float3 __attribute__((overloadable)) smoothstep(float3, float3, float3); +extern float4 __attribute__((overloadable)) smoothstep(float4, float4, float4); +extern float2 __attribute__((overloadable)) smoothstep(float, float, float2); +extern float3 __attribute__((overloadable)) smoothstep(float, float, float3); +extern float4 __attribute__((overloadable)) smoothstep(float, float, float4); + +static float __attribute__((overloadable)) sign(float v) { + if (v > 0) return 1.f; + if (v < 0) return -1.f; + return v; +} +DEF_FUNC_1(sign) + +// 6.11.5 +static float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs) { + float3 r; + r.x = lhs.y * rhs.z - lhs.z * rhs.y; + r.y = lhs.z * rhs.x - lhs.x * rhs.z; + r.z = lhs.x * rhs.y - lhs.y * rhs.x; + return r; +} + +static float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs) { + float4 r; + r.x = lhs.y * rhs.z - lhs.z * rhs.y; + r.y = lhs.z * rhs.x - lhs.x * rhs.z; + r.z = lhs.x * rhs.y - lhs.y * rhs.x; + r.w = 0.f; + return r; +} + +static float __attribute__((overloadable)) dot(float lhs, float rhs) { + return lhs * rhs; +} +static float __attribute__((overloadable)) dot(float2 lhs, float2 rhs) { + return lhs.x*rhs.x + lhs.y*rhs.y; +} +static float __attribute__((overloadable)) dot(float3 lhs, float3 rhs) { + return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; +} +static float __attribute__((overloadable)) dot(float4 lhs, float4 rhs) { + return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z + lhs.w*rhs.w; +} + +static float __attribute__((overloadable)) length(float v) { + return v; +} +static float __attribute__((overloadable)) length(float2 v) { + return sqrt(v.x*v.x + v.y*v.y); +} +static float __attribute__((overloadable)) length(float3 v) { + return sqrt(v.x*v.x + v.y*v.y + v.z*v.z); +} +static float __attribute__((overloadable)) length(float4 v) { + return sqrt(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); +} + +static float __attribute__((overloadable)) distance(float lhs, float rhs) { + return length(lhs - rhs); +} +static float __attribute__((overloadable)) distance(float2 lhs, float2 rhs) { + return length(lhs - rhs); +} +static float __attribute__((overloadable)) distance(float3 lhs, float3 rhs) { + return length(lhs - rhs); +} +static float __attribute__((overloadable)) distance(float4 lhs, float4 rhs) { + return length(lhs - rhs); +} + +static float __attribute__((overloadable)) normalize(float v) { + return 1.f; +} +static float2 __attribute__((overloadable)) normalize(float2 v) { + return v / length(v); +} +static float3 __attribute__((overloadable)) normalize(float3 v) { + return v / length(v); +} +static float4 __attribute__((overloadable)) normalize(float4 v) { + return v / length(v); +} + + +#endif diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh new file mode 100644 index 0000000..9950184 --- /dev/null +++ b/libs/rs/scriptc/rs_core.rsh @@ -0,0 +1,916 @@ +#ifndef __RS_CORE_RSH__ +#define __RS_CORE_RSH__ + +// Debugging, print to the LOG a description string and a value. +extern void __attribute__((overloadable)) + rsDebug(const char *, float); +extern void __attribute__((overloadable)) + rsDebug(const char *, float, float); +extern void __attribute__((overloadable)) + rsDebug(const char *, float, float, float); +extern void __attribute__((overloadable)) + rsDebug(const char *, float, float, float, float); +extern void __attribute__((overloadable)) + rsDebug(const char *, const rs_matrix4x4 *); +extern void __attribute__((overloadable)) + rsDebug(const char *, const rs_matrix3x3 *); +extern void __attribute__((overloadable)) + rsDebug(const char *, const rs_matrix2x2 *); +extern void __attribute__((overloadable)) + rsDebug(const char *, int); +extern void __attribute__((overloadable)) + rsDebug(const char *, uint); +extern void __attribute__((overloadable)) + rsDebug(const char *, const void *); +#define RS_DEBUG(a) rsDebug(#a, a) +#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__) + +static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) { + rsDebug(s, v.x, v.y); +} +static void __attribute__((overloadable)) rsDebug(const char *s, float3 v) { + rsDebug(s, v.x, v.y, v.z); +} +static void __attribute__((overloadable)) rsDebug(const char *s, float4 v) { + rsDebug(s, v.x, v.y, v.z, v.w); +} + +static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b) +{ + uchar4 c; + c.x = (uchar)(r * 255.f); + c.y = (uchar)(g * 255.f); + c.z = (uchar)(b * 255.f); + c.w = 255; + return c; +} + +static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a) +{ + uchar4 c; + c.x = (uchar)(r * 255.f); + c.y = (uchar)(g * 255.f); + c.z = (uchar)(b * 255.f); + c.w = (uchar)(a * 255.f); + return c; +} + +static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color) +{ + color *= 255.f; + uchar4 c = {color.x, color.y, color.z, 255}; + return c; +} + +static uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color) +{ + color *= 255.f; + uchar4 c = {color.x, color.y, color.z, color.w}; + return c; +} + +static float4 rsUnpackColor8888(uchar4 c) +{ + float4 ret = (float4)0.0039156862745f; + ret *= convert_float4(c); + return ret; +} + +//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float r, float g, float b); +//extern uchar4 __attribute__((overloadable)) rsPackColorTo565(float3); +//extern float4 rsUnpackColor565(uchar4); + + +///////////////////////////////////////////////////// +// Matrix ops +///////////////////////////////////////////////////// + +static void __attribute__((overloadable)) +rsMatrixSet(rs_matrix4x4 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 4 + col] = v; +} + +static float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix4x4 *m, uint32_t row, uint32_t col) { + return m->m[row * 4 + col]; +} + +static void __attribute__((overloadable)) +rsMatrixSet(rs_matrix3x3 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 3 + col] = v; +} + +static float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix3x3 *m, uint32_t row, uint32_t col) { + return m->m[row * 3 + col]; +} + +static void __attribute__((overloadable)) +rsMatrixSet(rs_matrix2x2 *m, uint32_t row, uint32_t col, float v) { + m->m[row * 2 + col] = v; +} + +static float __attribute__((overloadable)) +rsMatrixGet(const rs_matrix2x2 *m, uint32_t row, uint32_t col) { + return m->m[row * 2 + col]; +} + +static void __attribute__((overloadable)) +rsMatrixLoadIdentity(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 __attribute__((overloadable)) +rsMatrixLoadIdentity(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 __attribute__((overloadable)) +rsMatrixLoadIdentity(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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[3]; + m->m[5] = v->m[4]; + m->m[6] = 0.f; + m->m[7] = 0.f; + m->m[8] = v->m[6]; + m->m[9] = v->m[7]; + 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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoad(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 __attribute__((overloadable)) +rsMatrixLoadRotate(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 __attribute__((overloadable)) +rsMatrixLoadScale(rs_matrix4x4 *m, float x, float y, float z) { + rsMatrixLoadIdentity(m); + m->m[0] = x; + m->m[5] = y; + m->m[10] = z; +} + +static void __attribute__((overloadable)) +rsMatrixLoadTranslate(rs_matrix4x4 *m, float x, float y, float z) { + rsMatrixLoadIdentity(m); + m->m[12] = x; + m->m[13] = y; + m->m[14] = z; +} + +static void __attribute__((overloadable)) +rsMatrixLoadMultiply(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 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, const rs_matrix4x4 *rhs) { + rs_matrix4x4 mt; + rsMatrixLoadMultiply(&mt, m, rhs); + rsMatrixLoad(m, &mt); +} + +static void __attribute__((overloadable)) +rsMatrixLoadMultiply(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 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, const rs_matrix3x3 *rhs) { + rs_matrix3x3 mt; + rsMatrixLoadMultiply(&mt, m, rhs); + rsMatrixLoad(m, &mt); +} + +static void __attribute__((overloadable)) +rsMatrixLoadMultiply(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 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix2x2 *m, const rs_matrix2x2 *rhs) { + rs_matrix2x2 mt; + rsMatrixLoadMultiply(&mt, m, rhs); + rsMatrixLoad(m, &mt); +} + +static void __attribute__((overloadable)) +rsMatrixRotate(rs_matrix4x4 *m, float rot, float x, float y, float z) { + rs_matrix4x4 m1; + rsMatrixLoadRotate(&m1, rot, x, y, z); + rsMatrixMultiply(m, &m1); +} + +static void __attribute__((overloadable)) +rsMatrixScale(rs_matrix4x4 *m, float x, float y, float z) { + rs_matrix4x4 m1; + rsMatrixLoadScale(&m1, x, y, z); + rsMatrixMultiply(m, &m1); +} + +static void __attribute__((overloadable)) +rsMatrixTranslate(rs_matrix4x4 *m, float x, float y, float z) { + rs_matrix4x4 m1; + rsMatrixLoadTranslate(&m1, x, y, z); + rsMatrixMultiply(m, &m1); +} + +static void __attribute__((overloadable)) +rsMatrixLoadOrtho(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { + rsMatrixLoadIdentity(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 __attribute__((overloadable)) +rsMatrixLoadFrustum(rs_matrix4x4 *m, float left, float right, float bottom, float top, float near, float far) { + rsMatrixLoadIdentity(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 __attribute__((overloadable)) +rsMatrixLoadPerspective(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; + rsMatrixLoadFrustum(m, left, right, bottom, top, near, far); +} + +static float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float4 in) { + float4 ret; + ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + (m->m[12] * in.w); + ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + (m->m[9] * in.z) + (m->m[13] * in.w); + ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + (m->m[10] * in.z) + (m->m[14] * in.w); + ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + (m->m[11] * in.z) + (m->m[15] * in.w); + return ret; +} + +static float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float3 in) { + float4 ret; + ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + (m->m[8] * in.z) + m->m[12]; + ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + (m->m[9] * in.z) + m->m[13]; + ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + (m->m[10] * in.z) + m->m[14]; + ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + (m->m[11] * in.z) + m->m[15]; + return ret; +} + +static float4 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix4x4 *m, float2 in) { + float4 ret; + ret.x = (m->m[0] * in.x) + (m->m[4] * in.y) + m->m[12]; + ret.y = (m->m[1] * in.x) + (m->m[5] * in.y) + m->m[13]; + ret.z = (m->m[2] * in.x) + (m->m[6] * in.y) + m->m[14]; + ret.w = (m->m[3] * in.x) + (m->m[7] * in.y) + m->m[15]; + return ret; +} + +static float3 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, float3 in) { + float3 ret; + ret.x = (m->m[0] * in.x) + (m->m[3] * in.y) + (m->m[6] * in.z); + ret.y = (m->m[1] * in.x) + (m->m[4] * in.y) + (m->m[7] * in.z); + ret.z = (m->m[2] * in.x) + (m->m[5] * in.y) + (m->m[8] * in.z); + return ret; +} + +static float3 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix3x3 *m, float2 in) { + float3 ret; + ret.x = (m->m[0] * in.x) + (m->m[3] * in.y); + ret.y = (m->m[1] * in.x) + (m->m[4] * in.y); + ret.z = (m->m[2] * in.x) + (m->m[5] * in.y); + return ret; +} + +static float2 __attribute__((overloadable)) +rsMatrixMultiply(rs_matrix2x2 *m, float2 in) { + float2 ret; + ret.x = (m->m[0] * in.x) + (m->m[2] * in.y); + ret.y = (m->m[1] * in.x) + (m->m[3] * in.y); + return ret; +} + +// Returns true if the matrix was successfully inversed +static bool __attribute__((overloadable)) +rsMatrixInverse(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 __attribute__((overloadable)) +rsMatrixInverseTranspose(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; +} + +static void __attribute__((overloadable)) +rsMatrixTranspose(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; + } + } +} + +static void __attribute__((overloadable)) +rsMatrixTranspose(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 __attribute__((overloadable)) +rsMatrixTranspose(rs_matrix2x2 *m) { + float temp = m->m[1]; + m->m[1] = m->m[2]; + m->m[2] = temp; +} + +///////////////////////////////////////////////////// +// quaternion ops +///////////////////////////////////////////////////// + +static void __attribute__((overloadable)) +rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) { + q->w = w; + q->x = x; + q->y = y; + q->z = z; +} + +static void __attribute__((overloadable)) +rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) { + q->w = rhs->w; + q->x = rhs->x; + q->y = rhs->y; + q->z = rhs->z; +} + +static void __attribute__((overloadable)) +rsQuaternionMultiply(rs_quaternion *q, float s) { + q->w *= s; + q->x *= s; + q->y *= s; + q->z *= s; +} + +static void __attribute__((overloadable)) +rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) { + q->w = -q->x*rhs->x - q->y*rhs->y - q->z*rhs->z + q->w*rhs->w; + q->x = q->x*rhs->w + q->y*rhs->z - q->z*rhs->y + q->w*rhs->x; + q->y = -q->x*rhs->z + q->y*rhs->w + q->z*rhs->z + q->w*rhs->y; + q->z = q->x*rhs->y - q->y*rhs->x + q->z*rhs->w + q->w*rhs->z; +} + +static void +rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) { + q->w *= rhs->w; + q->x *= rhs->x; + q->y *= rhs->y; + q->z *= rhs->z; +} + +static void +rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) { + rot *= (float)(M_PI / 180.0f) * 0.5f; + float c = cos(rot); + float s = sin(rot); + + q->w = c; + q->x = x * s; + q->y = y * s; + q->z = z * s; +} + +static void +rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) { + 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; + } + rsQuaternionLoadRotateUnit(q, rot, x, y, z); +} + +static void +rsQuaternionConjugate(rs_quaternion *q) { + q->x = -q->x; + q->y = -q->y; + q->z = -q->z; +} + +static float +rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) { + return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z; +} + +static void +rsQuaternionNormalize(rs_quaternion *q) { + const float len = rsQuaternionDot(q, q); + if (len != 1) { + const float recipLen = 1.f / sqrt(len); + rsQuaternionMultiply(q, recipLen); + } +} + +static void +rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) { + if(t <= 0.0f) { + rsQuaternionSet(q, q0); + return; + } + if(t >= 1.0f) { + rsQuaternionSet(q, q1); + return; + } + + rs_quaternion tempq0, tempq1; + rsQuaternionSet(&tempq0, q0); + rsQuaternionSet(&tempq1, q1); + + float angle = rsQuaternionDot(q0, q1); + if(angle < 0) { + rsQuaternionMultiply(&tempq0, -1.0f); + angle *= -1.0f; + } + + float scale, invScale; + if (angle + 1.0f > 0.05f) { + if (1.0f - angle >= 0.05f) { + float theta = acos(angle); + float invSinTheta = 1.0f / sin(theta); + scale = sin(theta * (1.0f - t)) * invSinTheta; + invScale = sin(theta * t) * invSinTheta; + } + else { + scale = 1.0f - t; + invScale = t; + } + } + else { + rsQuaternionSet(&tempq1, tempq0.z, -tempq0.y, tempq0.x, -tempq0.w); + scale = sin(M_PI * (0.5f - t)); + invScale = sin(M_PI * t); + } + + rsQuaternionSet(q, tempq0.w*scale + tempq1.w*invScale, tempq0.x*scale + tempq1.x*invScale, + tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale); +} + +static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) { + float x2 = 2.0f * q->x * q->x; + float y2 = 2.0f * q->y * q->y; + float z2 = 2.0f * q->z * q->z; + float xy = 2.0f * q->x * q->y; + float wz = 2.0f * q->w * q->z; + float xz = 2.0f * q->x * q->z; + float wy = 2.0f * q->w * q->y; + float wx = 2.0f * q->w * q->x; + float yz = 2.0f * q->y * q->z; + + m->m[0] = 1.0f - y2 - z2; + m->m[1] = xy - wz; + m->m[2] = xz + wy; + m->m[3] = 0.0f; + + m->m[4] = xy + wz; + m->m[5] = 1.0f - x2 - z2; + m->m[6] = yz - wx; + m->m[7] = 0.0f; + + m->m[8] = xz - wy; + m->m[9] = yz - wx; + m->m[10] = 1.0f - x2 - y2; + m->m[11] = 0.0f; + + m->m[12] = 0.0f; + m->m[13] = 0.0f; + m->m[14] = 0.0f; + m->m[15] = 1.0f; +} + +///////////////////////////////////////////////////// +// utility funcs +///////////////////////////////////////////////////// +void __attribute__((overloadable)) +rsExtractFrustumPlanes(const rs_matrix4x4 *modelViewProj, + float4 *left, float4 *right, + float4 *top, float4 *bottom, + float4 *near, float4 *far) { + // x y z w = a b c d in the plane equation + left->x = modelViewProj->m[3] + modelViewProj->m[0]; + left->y = modelViewProj->m[7] + modelViewProj->m[4]; + left->z = modelViewProj->m[11] + modelViewProj->m[8]; + left->w = modelViewProj->m[15] + modelViewProj->m[12]; + + right->x = modelViewProj->m[3] - modelViewProj->m[0]; + right->y = modelViewProj->m[7] - modelViewProj->m[4]; + right->z = modelViewProj->m[11] - modelViewProj->m[8]; + right->w = modelViewProj->m[15] - modelViewProj->m[12]; + + top->x = modelViewProj->m[3] - modelViewProj->m[1]; + top->y = modelViewProj->m[7] - modelViewProj->m[5]; + top->z = modelViewProj->m[11] - modelViewProj->m[9]; + top->w = modelViewProj->m[15] - modelViewProj->m[13]; + + bottom->x = modelViewProj->m[3] + modelViewProj->m[1]; + bottom->y = modelViewProj->m[7] + modelViewProj->m[5]; + bottom->z = modelViewProj->m[11] + modelViewProj->m[9]; + bottom->w = modelViewProj->m[15] + modelViewProj->m[13]; + + near->x = modelViewProj->m[3] + modelViewProj->m[2]; + near->y = modelViewProj->m[7] + modelViewProj->m[6]; + near->z = modelViewProj->m[11] + modelViewProj->m[10]; + near->w = modelViewProj->m[15] + modelViewProj->m[14]; + + far->x = modelViewProj->m[3] - modelViewProj->m[2]; + far->y = modelViewProj->m[7] - modelViewProj->m[6]; + far->z = modelViewProj->m[11] - modelViewProj->m[10]; + far->w = modelViewProj->m[15] - modelViewProj->m[14]; + + float len = length(left->xyz); + *left /= len; + len = length(right->xyz); + *right /= len; + len = length(top->xyz); + *top /= len; + len = length(bottom->xyz); + *bottom /= len; + len = length(near->xyz); + *near /= len; + len = length(far->xyz); + *far /= len; +} + +bool __attribute__((overloadable)) +rsIsSphereInFrustum(float4 *sphere, + float4 *left, float4 *right, + float4 *top, float4 *bottom, + float4 *near, float4 *far) { + + float distToCenter = dot(left->xyz, sphere->xyz) + left->w; + if(distToCenter < -sphere->w) { + return false; + } + distToCenter = dot(right->xyz, sphere->xyz) + right->w; + if(distToCenter < -sphere->w) { + return false; + } + distToCenter = dot(top->xyz, sphere->xyz) + top->w; + if(distToCenter < -sphere->w) { + return false; + } + distToCenter = dot(bottom->xyz, sphere->xyz) + bottom->w; + if(distToCenter < -sphere->w) { + return false; + } + distToCenter = dot(near->xyz, sphere->xyz) + near->w; + if(distToCenter < -sphere->w) { + return false; + } + distToCenter = dot(far->xyz, sphere->xyz) + far->w; + if(distToCenter < -sphere->w) { + return false; + } + return true; +} + + +///////////////////////////////////////////////////// +// int ops +///////////////////////////////////////////////////// + +__inline__ static uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) { + return amount < low ? low : (amount > high ? high : amount); +} +__inline__ static int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) { + return amount < low ? low : (amount > high ? high : amount); +} +__inline__ static ushort __attribute__((overloadable, always_inline)) rsClamp(ushort amount, ushort low, ushort high) { + return amount < low ? low : (amount > high ? high : amount); +} +__inline__ static short __attribute__((overloadable, always_inline)) rsClamp(short amount, short low, short high) { + return amount < low ? low : (amount > high ? high : amount); +} +__inline__ static uchar __attribute__((overloadable, always_inline)) rsClamp(uchar amount, uchar low, uchar high) { + return amount < low ? low : (amount > high ? high : amount); +} +__inline__ static char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) { + return amount < low ? low : (amount > high ? high : amount); +} + + + +#endif + diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh index 70cd562..ac6f8cc 100644 --- a/libs/rs/scriptc/rs_graphics.rsh +++ b/libs/rs/scriptc/rs_graphics.rsh @@ -1,65 +1,112 @@ - - -extern float2 vec2Rand(float len); - -extern float3 float3Norm(float3); -extern float float3Length(float3); -extern float3 float3Add(float3 lhs, float3 rhs); -extern float3 float3Sub(float3 lhs, float3 rhs); -extern float3 float3Cross(float3 lhs, float3 rhs); -extern float float3Dot(float3 lhs, float3 rhs); -extern float3 float3Scale(float3 v, float scale); - -extern float4 float4Add(float4 lhs, float4 rhs); -extern float4 float4Sub(float4 lhs, float4 rhs); -extern float4 float4Cross(float4 lhs, float4 rhs); -extern float float4Dot(float4 lhs, float4 rhs); -extern float4 float4Scale(float4 v, float scale); - - // context -extern void bindProgramFragment(rs_program_fragment); -extern void bindProgramStore(rs_program_store); -extern void bindProgramVertex(rs_program_vertex); - -extern void bindSampler(rs_program_fragment, int slot, rs_sampler); -extern void bindSampler(rs_program_fragment, int slot, rs_allocation); - -extern void vpLoadModelMatrix(const float *); -extern void vpLoadTextureMatrix(const float *); - - -// drawing -extern void drawRect(float x1, float y1, float x2, float y2, float z); -extern void 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); -extern void 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); -extern void drawSprite(float x, float y, float z, float w, float h); -extern void drawSpriteScreenspace(float x, float y, float z, float w, float h); -extern void drawLine(float x1, float y1, float z1, float x2, float y2, float z2); -extern void drawPoint(float x1, float y1, float z1); -extern void drawSimpleMesh(int ism); -extern void drawSimpleMeshRange(int ism, int start, int len); - +#ifndef __RS_GRAPHICS_RSH__ +#define __RS_GRAPHICS_RSH__ + +#include "rs_math.rsh" + + +// Bind a ProgramFragment to the RS context. +extern void __attribute__((overloadable)) + rsgBindProgramFragment(rs_program_fragment); +extern void __attribute__((overloadable)) + rsgBindProgramStore(rs_program_store); +extern void __attribute__((overloadable)) + rsgBindProgramVertex(rs_program_vertex); +extern void __attribute__((overloadable)) + rsgBindProgramRaster(rs_program_raster); + +extern void __attribute__((overloadable)) + rsgBindSampler(rs_program_fragment, uint slot, rs_sampler); +extern void __attribute__((overloadable)) + rsgBindTexture(rs_program_fragment, uint slot, rs_allocation); + +extern void __attribute__((overloadable)) + rsgProgramVertexLoadProjectionMatrix(const rs_matrix4x4 *); +extern void __attribute__((overloadable)) + rsgProgramVertexLoadModelMatrix(const rs_matrix4x4 *); +extern void __attribute__((overloadable)) + rsgProgramVertexLoadTextureMatrix(const rs_matrix4x4 *); + +extern void __attribute__((overloadable)) + rsgProgramVertexGetProjectionMatrix(rs_matrix4x4 *); + +extern void __attribute__((overloadable)) + rsgProgramFragmentConstantColor(rs_program_fragment, float, float, float, float); + +extern uint __attribute__((overloadable)) + rsgGetWidth(void); +extern uint __attribute__((overloadable)) + rsgGetHeight(void); + +extern void __attribute__((overloadable)) + rsgUploadToTexture(rs_allocation); +extern void __attribute__((overloadable)) + rsgUploadToTexture(rs_allocation, uint mipLevel); +extern void __attribute__((overloadable)) + rsgUploadToBufferObject(rs_allocation); + +extern void __attribute__((overloadable)) + rsgDrawRect(float x1, float y1, float x2, float y2, float z); +extern void __attribute__((overloadable)) + rsgDrawQuad(float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4); +extern void __attribute__((overloadable)) + rsgDrawQuadTexCoords(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); +extern void __attribute__((overloadable)) + rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h); + +extern void __attribute__((overloadable)) + rsgDrawMesh(rs_mesh ism); +extern void __attribute__((overloadable)) + rsgDrawMesh(rs_mesh ism, uint primitiveIndex); +extern void __attribute__((overloadable)) + rsgDrawMesh(rs_mesh ism, uint primitiveIndex, uint start, uint len); + +extern void __attribute__((overloadable)) + rsgClearColor(float, float, float, float); +extern void __attribute__((overloadable)) + rsgClearDepth(float); + +extern void __attribute__((overloadable)) + rsgDrawText(const char *, int x, int y); +extern void __attribute__((overloadable)) + rsgDrawText(rs_allocation, int x, int y); +extern void __attribute__((overloadable)) + rsgBindFont(rs_font); +extern void __attribute__((overloadable)) + rsgFontColor(float, float, float, float); +// Returns the bounding box of the text relative to (0, 0) +// Any of left, right, top, bottom could be NULL +extern void __attribute__((overloadable)) + rsgMeasureText(const char *, int *left, int *right, int *top, int *bottom); +extern void __attribute__((overloadable)) + rsgMeasureText(rs_allocation, int *left, int *right, int *top, int *bottom); + +extern void __attribute__((overloadable)) + rsgMeshComputeBoundingBox(rs_mesh mesh, float *minX, float *minY, float *minZ, + float *maxX, float *maxY, float *maxZ); +void __attribute__((overloadable)) +rsgMeshComputeBoundingBox(rs_mesh mesh, float3 *bBoxMin, float3 *bBoxMax) { + float x1, y1, z1, x2, y2, z2; + rsgMeshComputeBoundingBox(mesh, &x1, &y1, &z1, &x2, &y2, &z2); + bBoxMin->x = x1; + bBoxMin->y = y1; + bBoxMin->z = z1; + bBoxMax->x = x2; + bBoxMax->y = y2; + bBoxMax->z = z2; +} + +/////////////////////////////////////////////////////// // misc -extern void pfClearColor(float, float, float, float); -extern void color(float, float, float, float); -extern void hsb(float, float, float, float); -extern void hsbToRgb(float, float, float, float*); -extern int hsbToAbgr(float, float, float, float); - -extern void uploadToTexture(int, int); -extern void uploadToBufferObject(int); - -extern int colorFloatRGBAtoUNorm8(float, float, float, float); -extern int colorFloatRGBto565(float, float, float); - -extern int getWidth(); -extern int getHeight(); - -extern int sendToClient(void *data, int cmdID, int len, int waitForSpace); - -extern void debugF(const char *, float); -extern void debugI32(const char *, int); -extern void debugHexI32(const char *, int); +// Depricated +extern void __attribute__((overloadable)) + color(float, float, float, float); +#endif diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh index 613c7ca..d059997 100644 --- a/libs/rs/scriptc/rs_math.rsh +++ b/libs/rs/scriptc/rs_math.rsh @@ -1,287 +1,194 @@ -// Float ops - -extern float __attribute__((overloadable)) abs(float); -extern float2 __attribute__((overloadable)) abs(float2); -extern float3 __attribute__((overloadable)) abs(float3); -extern float4 __attribute__((overloadable)) abs(float4); -extern float8 __attribute__((overloadable)) abs(float8); -extern float16 __attribute__((overloadable)) abs(float16); - -extern float __attribute__((overloadable)) acos(float); -extern float2 __attribute__((overloadable)) acos(float2); -extern float3 __attribute__((overloadable)) acos(float3); -extern float4 __attribute__((overloadable)) acos(float4); -extern float8 __attribute__((overloadable)) acos(float8); -extern float16 __attribute__((overloadable)) acos(float16); - -extern float __attribute__((overloadable)) asin(float); -extern float2 __attribute__((overloadable)) asin(float2); -extern float3 __attribute__((overloadable)) asin(float3); -extern float4 __attribute__((overloadable)) asin(float4); -extern float8 __attribute__((overloadable)) asin(float8); -extern float16 __attribute__((overloadable)) asin(float16); - -extern float __attribute__((overloadable)) atan(float); -extern float2 __attribute__((overloadable)) atan(float2); -extern float3 __attribute__((overloadable)) atan(float3); -extern float4 __attribute__((overloadable)) atan(float4); -extern float8 __attribute__((overloadable)) atan(float8); -extern float16 __attribute__((overloadable)) atan(float16); - -extern float __attribute__((overloadable)) atan2(float, float); -extern float2 __attribute__((overloadable)) atan2(float2, float2); -extern float3 __attribute__((overloadable)) atan2(float3, float3); -extern float4 __attribute__((overloadable)) atan2(float4, float4); -extern float8 __attribute__((overloadable)) atan2(float8, float8); -extern float16 __attribute__((overloadable)) atan2(float16, float16); - -extern float __attribute__((overloadable)) ceil(float); -extern float2 __attribute__((overloadable)) ceil(float2); -extern float3 __attribute__((overloadable)) ceil(float3); -extern float4 __attribute__((overloadable)) ceil(float4); -extern float8 __attribute__((overloadable)) ceil(float8); -extern float16 __attribute__((overloadable)) ceil(float16); - -extern float __attribute__((overloadable)) clamp(float, float, float); -extern float2 __attribute__((overloadable)) clamp(float2, float2, float2); -extern float3 __attribute__((overloadable)) clamp(float3, float3, float3); -extern float4 __attribute__((overloadable)) clamp(float4, float4, float4); -extern float8 __attribute__((overloadable)) clamp(float8, float8, float8); -extern float16 __attribute__((overloadable)) clamp(float16, float16, float16); -extern float __attribute__((overloadable)) clamp(float, float, float); -extern float2 __attribute__((overloadable)) clamp(float2, float, float); -extern float3 __attribute__((overloadable)) clamp(float3, float, float); -extern float4 __attribute__((overloadable)) clamp(float4, float, float); -extern float8 __attribute__((overloadable)) clamp(float8, float, float); -extern float16 __attribute__((overloadable)) clamp(float16, float, float); - -extern float __attribute__((overloadable)) copysign(float, float); -extern float2 __attribute__((overloadable)) copysign(float2, float2); -extern float3 __attribute__((overloadable)) copysign(float3, float3); -extern float4 __attribute__((overloadable)) copysign(float4, float4); -extern float8 __attribute__((overloadable)) copysign(float8, float8); -extern float16 __attribute__((overloadable)) copysign(float16, float16); - -extern float __attribute__((overloadable)) cos(float); -extern float2 __attribute__((overloadable)) cos(float2); -extern float3 __attribute__((overloadable)) cos(float3); -extern float4 __attribute__((overloadable)) cos(float4); -extern float8 __attribute__((overloadable)) cos(float8); -extern float16 __attribute__((overloadable)) cos(float16); - -extern float __attribute__((overloadable)) degrees(float); -extern float2 __attribute__((overloadable)) degrees(float2); -extern float3 __attribute__((overloadable)) degrees(float3); -extern float4 __attribute__((overloadable)) degrees(float4); -extern float8 __attribute__((overloadable)) degrees(float8); -extern float16 __attribute__((overloadable)) degrees(float16); - -extern float __attribute__((overloadable)) exp(float); -extern float2 __attribute__((overloadable)) exp(float2); -extern float3 __attribute__((overloadable)) exp(float3); -extern float4 __attribute__((overloadable)) exp(float4); -extern float8 __attribute__((overloadable)) exp(float8); -extern float16 __attribute__((overloadable)) exp(float16); - -extern float __attribute__((overloadable)) exp2(float); -extern float2 __attribute__((overloadable)) exp2(float2); -extern float3 __attribute__((overloadable)) exp2(float3); -extern float4 __attribute__((overloadable)) exp2(float4); -extern float8 __attribute__((overloadable)) exp2(float8); -extern float16 __attribute__((overloadable)) exp2(float16); - -extern float __attribute__((overloadable)) exp10(float); -extern float2 __attribute__((overloadable)) exp10(float2); -extern float3 __attribute__((overloadable)) exp10(float3); -extern float4 __attribute__((overloadable)) exp10(float4); -extern float8 __attribute__((overloadable)) exp10(float8); -extern float16 __attribute__((overloadable)) exp10(float16); - -extern float __attribute__((overloadable)) fabs(float); -extern float2 __attribute__((overloadable)) fabs(float2); -extern float3 __attribute__((overloadable)) fabs(float3); -extern float4 __attribute__((overloadable)) fabs(float4); -extern float8 __attribute__((overloadable)) fabs(float8); -extern float16 __attribute__((overloadable)) fabs(float16); - -extern float __attribute__((overloadable)) floor(float); -extern float2 __attribute__((overloadable)) floor(float2); -extern float3 __attribute__((overloadable)) floor(float3); -extern float4 __attribute__((overloadable)) floor(float4); -extern float8 __attribute__((overloadable)) floor(float8); -extern float16 __attribute__((overloadable)) floor(float16); - -extern float __attribute__((overloadable)) fmax(float, float); -extern float2 __attribute__((overloadable)) fmax(float2, float2); -extern float3 __attribute__((overloadable)) fmax(float3, float3); -extern float4 __attribute__((overloadable)) fmax(float4, float4); -extern float8 __attribute__((overloadable)) fmax(float8, float8); -extern float16 __attribute__((overloadable)) fmax(float16, float16); -extern float2 __attribute__((overloadable)) fmax(float2, float); -extern float3 __attribute__((overloadable)) fmax(float3, float); -extern float4 __attribute__((overloadable)) fmax(float4, float); -extern float8 __attribute__((overloadable)) fmax(float8, float); -extern float16 __attribute__((overloadable)) fmax(float16, float); - -extern float __attribute__((overloadable)) fmin(float, float); -extern float2 __attribute__((overloadable)) fmin(float2, float2); -extern float3 __attribute__((overloadable)) fmin(float3, float3); -extern float4 __attribute__((overloadable)) fmin(float4, float4); -extern float8 __attribute__((overloadable)) fmin(float8, float8); -extern float16 __attribute__((overloadable)) fmin(float16, float16); -extern float2 __attribute__((overloadable)) fmin(float2, float); -extern float3 __attribute__((overloadable)) fmin(float3, float); -extern float4 __attribute__((overloadable)) fmin(float4, float); -extern float8 __attribute__((overloadable)) fmin(float8, float); -extern float16 __attribute__((overloadable)) fmin(float16, float); - -extern float __attribute__((overloadable)) fmod(float, float); -extern float2 __attribute__((overloadable)) fmod(float2, float2); -extern float3 __attribute__((overloadable)) fmod(float3, float3); -extern float4 __attribute__((overloadable)) fmod(float4, float4); -extern float8 __attribute__((overloadable)) fmod(float8, float8); -extern float16 __attribute__((overloadable)) fmod(float16, float16); - -extern float __attribute__((overloadable)) log(float); -extern float2 __attribute__((overloadable)) log(float2); -extern float3 __attribute__((overloadable)) log(float3); -extern float4 __attribute__((overloadable)) log(float4); -extern float8 __attribute__((overloadable)) log(float8); -extern float16 __attribute__((overloadable)) log(float16); - -extern float __attribute__((overloadable)) log2(float); -extern float2 __attribute__((overloadable)) log2(float2); -extern float3 __attribute__((overloadable)) log2(float3); -extern float4 __attribute__((overloadable)) log2(float4); -extern float8 __attribute__((overloadable)) log2(float8); -extern float16 __attribute__((overloadable)) log2(float16); - -extern float __attribute__((overloadable)) log10(float); -extern float2 __attribute__((overloadable)) log10(float2); -extern float3 __attribute__((overloadable)) log10(float3); -extern float4 __attribute__((overloadable)) log10(float4); -extern float8 __attribute__((overloadable)) log10(float8); -extern float16 __attribute__((overloadable)) log10(float16); - -extern float __attribute__((overloadable)) max(float, float); -extern float2 __attribute__((overloadable)) max(float2, float2); -extern float3 __attribute__((overloadable)) max(float3, float3); -extern float4 __attribute__((overloadable)) max(float4, float4); -extern float8 __attribute__((overloadable)) max(float8, float8); -extern float16 __attribute__((overloadable)) max(float16, float16); - -extern float __attribute__((overloadable)) min(float, float); -extern float2 __attribute__((overloadable)) min(float2, float2); -extern float3 __attribute__((overloadable)) min(float3, float3); -extern float4 __attribute__((overloadable)) min(float4, float4); -extern float8 __attribute__((overloadable)) min(float8, float8); -extern float16 __attribute__((overloadable)) min(float16, float16); - -extern float __attribute__((overloadable)) mix(float, float, float); -extern float2 __attribute__((overloadable)) mix(float2, float2, float2); -extern float3 __attribute__((overloadable)) mix(float3, float3, float3); -extern float4 __attribute__((overloadable)) mix(float4, float4, float4); -extern float8 __attribute__((overloadable)) mix(float8, float8, float8); -extern float16 __attribute__((overloadable)) mix(float16, float16, float16); -extern float __attribute__((overloadable)) mix(float, float, float); -extern float2 __attribute__((overloadable)) mix(float2, float2, float); -extern float3 __attribute__((overloadable)) mix(float3, float3, float); -extern float4 __attribute__((overloadable)) mix(float4, float4, float); -extern float8 __attribute__((overloadable)) mix(float8, float8, float); -extern float16 __attribute__((overloadable)) mix(float16, float16, float); - -extern float __attribute__((overloadable)) pow(float, float); -extern float2 __attribute__((overloadable)) pow(float2, float2); -extern float3 __attribute__((overloadable)) pow(float3, float3); -extern float4 __attribute__((overloadable)) pow(float4, float4); -extern float8 __attribute__((overloadable)) pow(float8, float8); -extern float16 __attribute__((overloadable)) pow(float16, float16); - -extern float __attribute__((overloadable)) radians(float); -extern float2 __attribute__((overloadable)) radians(float2); -extern float3 __attribute__((overloadable)) radians(float3); -extern float4 __attribute__((overloadable)) radians(float4); -extern float8 __attribute__((overloadable)) radians(float8); -extern float16 __attribute__((overloadable)) radians(float16); - -extern float __attribute__((overloadable)) rint(float); -extern float2 __attribute__((overloadable)) rint(float2); -extern float3 __attribute__((overloadable)) rint(float3); -extern float4 __attribute__((overloadable)) rint(float4); -extern float8 __attribute__((overloadable)) rint(float8); -extern float16 __attribute__((overloadable)) rint(float16); - -extern float __attribute__((overloadable)) round(float); -extern float2 __attribute__((overloadable)) round(float2); -extern float3 __attribute__((overloadable)) round(float3); -extern float4 __attribute__((overloadable)) round(float4); -extern float8 __attribute__((overloadable)) round(float8); -extern float16 __attribute__((overloadable)) round(float16); - -extern float __attribute__((overloadable)) rsqrt(float); -extern float2 __attribute__((overloadable)) rsqrt(float2); -extern float3 __attribute__((overloadable)) rsqrt(float3); -extern float4 __attribute__((overloadable)) rsqrt(float4); -extern float8 __attribute__((overloadable)) rsqrt(float8); -extern float16 __attribute__((overloadable)) rsqrt(float16); - -extern float __attribute__((overloadable)) sign(float); -extern float2 __attribute__((overloadable)) sign(float2); -extern float3 __attribute__((overloadable)) sign(float3); -extern float4 __attribute__((overloadable)) sign(float4); -extern float8 __attribute__((overloadable)) sign(float8); -extern float16 __attribute__((overloadable)) sign(float16); - -extern float __attribute__((overloadable)) sin(float); -extern float2 __attribute__((overloadable)) sin(float2); -extern float3 __attribute__((overloadable)) sin(float3); -extern float4 __attribute__((overloadable)) sin(float4); -extern float8 __attribute__((overloadable)) sin(float8); -extern float16 __attribute__((overloadable)) sin(float16); - -extern float __attribute__((overloadable)) sqrt(float); -extern float2 __attribute__((overloadable)) sqrt(float2); -extern float3 __attribute__((overloadable)) sqrt(float3); -extern float4 __attribute__((overloadable)) sqrt(float4); -extern float8 __attribute__((overloadable)) sqrt(float8); -extern float16 __attribute__((overloadable)) sqrt(float16); - -extern float __attribute__((overloadable)) tan(float); -extern float2 __attribute__((overloadable)) tan(float2); -extern float3 __attribute__((overloadable)) tan(float3); -extern float4 __attribute__((overloadable)) tan(float4); -extern float8 __attribute__((overloadable)) tan(float8); -extern float16 __attribute__((overloadable)) tan(float16); - -extern float __attribute__((overloadable)) trunc(float); -extern float2 __attribute__((overloadable)) trunc(float2); -extern float3 __attribute__((overloadable)) trunc(float3); -extern float4 __attribute__((overloadable)) trunc(float4); -extern float8 __attribute__((overloadable)) trunc(float8); -extern float16 __attribute__((overloadable)) trunc(float16); - - - - - - -// Int ops - -extern int __attribute__((overloadable)) abs(int); -extern int2 __attribute__((overloadable)) abs(int2); -extern int3 __attribute__((overloadable)) abs(int3); -extern int4 __attribute__((overloadable)) abs(int4); -extern int8 __attribute__((overloadable)) abs(int8); -extern int16 __attribute__((overloadable)) abs(int16); - - - -/* -extern float modf(float, float); -extern float randf(float); -extern float randf2(float, float); -extern float fracf(float); -extern float lerpf(float, float, float); -extern float mapf(float, float, float, float, float); -*/ - +#ifndef __RS_MATH_RSH__ +#define __RS_MATH_RSH__ + +extern void __attribute__((overloadable)) + rsSetObject(rs_element *dst, rs_element src); +extern void __attribute__((overloadable)) + rsSetObject(rs_type *dst, rs_type src); +extern void __attribute__((overloadable)) + rsSetObject(rs_allocation *dst, rs_allocation src); +extern void __attribute__((overloadable)) + rsSetObject(rs_sampler *dst, rs_sampler src); +extern void __attribute__((overloadable)) + rsSetObject(rs_script *dst, rs_script src); +extern void __attribute__((overloadable)) + rsSetObject(rs_mesh *dst, rs_mesh src); +extern void __attribute__((overloadable)) + rsSetObject(rs_program_fragment *dst, rs_program_fragment src); +extern void __attribute__((overloadable)) + rsSetObject(rs_program_vertex *dst, rs_program_vertex src); +extern void __attribute__((overloadable)) + rsSetObject(rs_program_raster *dst, rs_program_raster src); +extern void __attribute__((overloadable)) + rsSetObject(rs_program_store *dst, rs_program_store src); +extern void __attribute__((overloadable)) + rsSetObject(rs_font *dst, rs_font src); + +extern void __attribute__((overloadable)) + rsClearObject(rs_element *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_type *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_allocation *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_sampler *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_script *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_mesh *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_program_fragment *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_program_vertex *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_program_raster *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_program_store *dst); +extern void __attribute__((overloadable)) + rsClearObject(rs_font *dst); + +extern bool __attribute__((overloadable)) + rsIsObject(rs_element); +extern bool __attribute__((overloadable)) + rsIsObject(rs_type); +extern bool __attribute__((overloadable)) + rsIsObject(rs_allocation); +extern bool __attribute__((overloadable)) + rsIsObject(rs_sampler); +extern bool __attribute__((overloadable)) + rsIsObject(rs_script); +extern bool __attribute__((overloadable)) + rsIsObject(rs_mesh); +extern bool __attribute__((overloadable)) + rsIsObject(rs_program_fragment); +extern bool __attribute__((overloadable)) + rsIsObject(rs_program_vertex); +extern bool __attribute__((overloadable)) + rsIsObject(rs_program_raster); +extern bool __attribute__((overloadable)) + rsIsObject(rs_program_store); +extern bool __attribute__((overloadable)) + rsIsObject(rs_font); + + + +// Allocations + +// Return the rs_allocation associated with a bound data +// pointer. +extern rs_allocation __attribute__((overloadable)) + rsGetAllocation(const void *); + +// Mark the allocation dirty and notify those using it +extern void __attribute__((overloadable)) + rsAllocationMarkDirty(rs_allocation); + +// Return the dimensions associated with an allocation. +extern uint32_t __attribute__((overloadable)) + rsAllocationGetDimX(rs_allocation); +extern uint32_t __attribute__((overloadable)) + rsAllocationGetDimY(rs_allocation); +extern uint32_t __attribute__((overloadable)) + rsAllocationGetDimZ(rs_allocation); +extern uint32_t __attribute__((overloadable)) + rsAllocationGetDimLOD(rs_allocation); +extern uint32_t __attribute__((overloadable)) + rsAllocationGetDimFaces(rs_allocation); + +// Extract a single element from an allocation. +extern const void * __attribute__((overloadable)) + rsGetElementAt(rs_allocation, uint32_t x); +extern const void * __attribute__((overloadable)) + rsGetElementAt(rs_allocation, uint32_t x, uint32_t y); +extern const void * __attribute__((overloadable)) + rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z); + +// Return a random value between 0 (or min_value) and max_malue. +extern int __attribute__((overloadable)) + rsRand(int max_value); +extern int __attribute__((overloadable)) + rsRand(int min_value, int max_value); +extern float __attribute__((overloadable)) + rsRand(float max_value); +extern float __attribute__((overloadable)) + rsRand(float min_value, float max_value); + +// return the fractional part of a float +// min(v - ((int)floor(v)), 0x1.fffffep-1f); +extern float __attribute__((overloadable)) + rsFrac(float); + +// time +extern int32_t __attribute__((overloadable)) + rsSecond(void); +extern int32_t __attribute__((overloadable)) + rsMinute(void); +extern int32_t __attribute__((overloadable)) + rsHour(void); +extern int32_t __attribute__((overloadable)) + rsDay(void); +extern int32_t __attribute__((overloadable)) + rsMonth(void); +extern int32_t __attribute__((overloadable)) + rsYear(void); + +// Return the current system clock in milliseconds +extern int64_t __attribute__((overloadable)) + rsUptimeMillis(void); + +// Return the current system clock in nanoseconds +extern int64_t __attribute__((overloadable)) + rsUptimeNanos(void); + +// Return the time in seconds since function was last called in this script. +extern float __attribute__((overloadable)) + rsGetDt(void); + +// Send a message back to the client. Will not block and returns true +// if the message was sendable and false if the fifo was full. +// A message ID is required. Data payload is optional. +extern bool __attribute__((overloadable)) + rsSendToClient(int cmdID); +extern bool __attribute__((overloadable)) + rsSendToClient(int cmdID, const void *data, uint len); + +// Send a message back to the client, blocking until the message is queued. +// A message ID is required. Data payload is optional. +extern void __attribute__((overloadable)) + rsSendToClientBlocking(int cmdID); +extern void __attribute__((overloadable)) + rsSendToClientBlocking(int cmdID, const void *data, uint len); + + +// Script to Script +enum rs_for_each_strategy { + RS_FOR_EACH_STRATEGY_SERIAL, + RS_FOR_EACH_STRATEGY_DONT_CARE, + RS_FOR_EACH_STRATEGY_DST_LINEAR, + RS_FOR_EACH_STRATEGY_TILE_SMALL, + RS_FOR_EACH_STRATEGY_TILE_MEDIUM, + RS_FOR_EACH_STRATEGY_TILE_LARGE +}; + +typedef struct rs_script_call { + enum rs_for_each_strategy strategy; + uint32_t xStart; + uint32_t xEnd; + uint32_t yStart; + uint32_t yEnd; + uint32_t zStart; + uint32_t zEnd; + uint32_t arrayStart; + uint32_t arrayEnd; +} rs_script_call_t; + +extern void __attribute__((overloadable)) + rsForEach(rs_script script, rs_allocation input, + rs_allocation output, const void * usrData); + +extern void __attribute__((overloadable)) + rsForEach(rs_script script, rs_allocation input, + rs_allocation output, const void * usrData, + const rs_script_call_t *); + +#endif diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh index 4198a74..212eb83 100644 --- a/libs/rs/scriptc/rs_types.rsh +++ b/libs/rs/scriptc/rs_types.rsh @@ -1,71 +1,77 @@ +#ifndef __RS_TYPES_RSH__ +#define __RS_TYPES_RSH__ typedef char int8_t; typedef short int16_t; typedef int int32_t; -//typedef long int64_t; +typedef long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; -//typedef long uint64_t; +typedef unsigned long long uint64_t; typedef uint8_t uchar; typedef uint16_t ushort; typedef uint32_t uint; -//typedef uint64_t ulong; - -typedef int rs_element; -typedef int rs_type; -typedef int rs_allocation; -typedef int rs_sampler; -typedef int rs_script; -typedef int rs_mesh; -typedef int rs_program_fragment; -typedef int rs_program_vertex; -typedef int rs_program_raster; -typedef int rs_program_store; +typedef uint64_t ulong; + +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_element; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_type; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_allocation; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sampler; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_script; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_fragment; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_vertex; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_raster; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_program_store; +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_font; + 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 float float8 __attribute__((ext_vector_type(8))); -typedef float float16 __attribute__((ext_vector_type(16))); typedef uchar uchar2 __attribute__((ext_vector_type(2))); typedef uchar uchar3 __attribute__((ext_vector_type(3))); typedef uchar uchar4 __attribute__((ext_vector_type(4))); -typedef uchar uchar8 __attribute__((ext_vector_type(8))); -typedef uchar uchar16 __attribute__((ext_vector_type(16))); typedef ushort ushort2 __attribute__((ext_vector_type(2))); typedef ushort ushort3 __attribute__((ext_vector_type(3))); typedef ushort ushort4 __attribute__((ext_vector_type(4))); -typedef ushort ushort8 __attribute__((ext_vector_type(8))); -typedef ushort ushort16 __attribute__((ext_vector_type(16))); 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 uint uint8 __attribute__((ext_vector_type(8))); -typedef uint uint16 __attribute__((ext_vector_type(16))); typedef char char2 __attribute__((ext_vector_type(2))); typedef char char3 __attribute__((ext_vector_type(3))); typedef char char4 __attribute__((ext_vector_type(4))); -typedef char char8 __attribute__((ext_vector_type(8))); -typedef char char16 __attribute__((ext_vector_type(16))); typedef short short2 __attribute__((ext_vector_type(2))); typedef short short3 __attribute__((ext_vector_type(3))); typedef short short4 __attribute__((ext_vector_type(4))); -typedef short short8 __attribute__((ext_vector_type(8))); -typedef short short16 __attribute__((ext_vector_type(16))); 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 int int8 __attribute__((ext_vector_type(8))); -typedef int int16 __attribute__((ext_vector_type(16))); +typedef struct { + float m[16]; +} rs_matrix4x4; + +typedef struct { + float m[9]; +} rs_matrix3x3; + +typedef struct { + float m[4]; +} rs_matrix2x2; + +typedef float4 rs_quaternion; + +#define RS_PACKED __attribute__((packed, aligned(4))) +#endif diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp index 9ff6930..b5f9c47 100644 --- a/libs/storage/IMountService.cpp +++ b/libs/storage/IMountService.cpp @@ -47,6 +47,7 @@ enum { TRANSACTION_unmountObb, TRANSACTION_isObbMounted, TRANSACTION_getMountedObbPath, + TRANSACTION_isExternalStorageEmulated, }; class BpMountService: public BpInterface<IMountService> diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 4bc5d9e..8f583f0 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -380,11 +380,6 @@ ssize_t SharedBufferClient::dequeue() { SharedBufferStack& stack( *mSharedStack ); - if (stack.head == tail && stack.available == mNumBuffers) { - LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d", - tail, stack.head, stack.available, stack.queued); - } - RWLock::AutoRLock _rd(mLock); const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD); diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index d44aab9..0994980 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -364,6 +364,13 @@ status_t Surface::writeToParcel( height = surface->mHeight; format = surface->mFormat; flags = surface->mFlags; + } else if (surface != 0 && surface->mSurface != 0) { + LOGW("Parceling invalid surface with non-NULL ISurface as NULL: " + "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, " + "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d", + surface->mSurface.get(), surface->mIdentity, surface->mWidth, + surface->mHeight, surface->mFormat, surface->mFlags, + surface->mInitCheck); } parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); parcel->writeInt32(identity); @@ -438,21 +445,15 @@ void Surface::init() mSharedBufferClient = new SharedBufferClient( mClient.getSharedClient(), token, 2, mIdentity); mInitCheck = mClient.getSharedClient()->validate(token); + } else { + LOGW("Not initializing the shared buffer client because token = %d", + token); } } } Surface::~Surface() { - // this is a client-side operation, the surface is destroyed, unmap - // its buffers in this process. - size_t size = mBuffers.size(); - for (size_t i=0 ; i<size ; i++) { - if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) { - getBufferMapper().unregisterBuffer(mBuffers[i]->handle); - } - } - // clear all references and trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. mBuffers.clear(); @@ -1011,7 +1012,20 @@ void Surface::setSwapRectangle(const Rect& r) { int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const { - return buffer->getIndex(); + int idx = buffer->getIndex(); + 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 + // was dequeued from an ANativeWindow. + for (int i = 0; i < mBuffers.size(); i++) { + if (buffer->handle == mBuffers[i]->handle) { + idx = mBuffers[i]->getIndex(); + break; + } + } + } + return idx; } status_t Surface::getBufferLocked(int index, @@ -1025,7 +1039,6 @@ status_t Surface::getBufferLocked(int index, // free the current buffer sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index)); if (currentBuffer != 0) { - getBufferMapper().unregisterBuffer(currentBuffer->handle); currentBuffer.clear(); } @@ -1033,7 +1046,7 @@ status_t Surface::getBufferLocked(int index, LOGE_IF(buffer==0, "ISurface::getBuffer(%d, %08x) returned NULL", index, usage); - if (buffer != 0) { // this should never happen by construction + if (buffer != 0) { // this should always happen by construction LOGE_IF(buffer->handle == NULL, "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) " "returned a buffer with a null handle", @@ -1041,13 +1054,8 @@ status_t Surface::getBufferLocked(int index, err = mSharedBufferClient->getStatus(); LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err); if (!err && buffer->handle != NULL) { - err = getBufferMapper().registerBuffer(buffer->handle); - LOGW_IF(err, "registerBuffer(...) failed %d (%s)", - err, strerror(-err)); - if (err == NO_ERROR) { - currentBuffer = buffer; - currentBuffer->setIndex(index); - } + currentBuffer = buffer; + currentBuffer->setIndex(index); } else { err = err<0 ? err : status_t(NO_MEMORY); } diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 519c277..436e064 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -77,6 +77,19 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, handle = inHandle; } +GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership) + : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), + mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer) +{ + width = buffer->width; + height = buffer->height; + stride = buffer->stride; + format = buffer->format; + usage = buffer->usage; + handle = buffer->handle; +} + GraphicBuffer::~GraphicBuffer() { if (handle) { @@ -87,12 +100,14 @@ GraphicBuffer::~GraphicBuffer() void GraphicBuffer::free_handle() { if (mOwner == ownHandle) { + mBufferMapper.unregisterBuffer(handle); native_handle_close(handle); native_handle_delete(const_cast<native_handle*>(handle)); } else if (mOwner == ownData) { GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); } + mWrappedBuffer = 0; } status_t GraphicBuffer::initCheck() const { @@ -253,6 +268,11 @@ status_t GraphicBuffer::unflatten(void const* buffer, size_t size, } mOwner = ownHandle; + + if (handle != 0) { + mBufferMapper.registerBuffer(handle); + } + return NO_ERROR; } diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 6ba19d7..84c3db8 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -2612,6 +2612,82 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } } +bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, + const sp<InputChannel>& toChannel) { +#if DEBUG_FOCUS + LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", + fromChannel->getName().string(), toChannel->getName().string()); +#endif + { // acquire lock + AutoMutex _l(mLock); + + const InputWindow* fromWindow = getWindowLocked(fromChannel); + const InputWindow* toWindow = getWindowLocked(toChannel); + if (! fromWindow || ! toWindow) { +#if DEBUG_FOCUS + LOGD("Cannot transfer focus because from or to window not found."); +#endif + return false; + } + if (fromWindow == toWindow) { +#if DEBUG_FOCUS + LOGD("Trivial transfer to same window."); +#endif + return true; + } + + bool found = false; + for (size_t i = 0; i < mTouchState.windows.size(); i++) { + const TouchedWindow& touchedWindow = mTouchState.windows[i]; + if (touchedWindow.window == fromWindow) { + int32_t oldTargetFlags = touchedWindow.targetFlags; + BitSet32 pointerIds = touchedWindow.pointerIds; + + mTouchState.windows.removeAt(i); + + int32_t newTargetFlags = 0; + if (oldTargetFlags & InputTarget::FLAG_FOREGROUND) { + newTargetFlags |= InputTarget::FLAG_FOREGROUND; + if (toWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) { + newTargetFlags |= InputTarget::FLAG_SPLIT; + } + } + mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds); + + found = true; + break; + } + } + + if (! found) { +#if DEBUG_FOCUS + LOGD("Focus transfer failed because from window did not have focus."); +#endif + return false; + } + + ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); + ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); + if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { + sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex); + sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex); + + fromConnection->inputState.copyPointerStateTo(toConnection->inputState); + synthesizeCancelationEventsForConnectionLocked(fromConnection, + InputState::CANCEL_POINTER_EVENTS, + "transferring touch focus from this window to another window"); + } + +#if DEBUG_FOCUS + logDispatchStateLocked(); +#endif + } // release lock + + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); + return true; +} + void InputDispatcher::logDispatchStateLocked() { String8 dump; dumpDispatchStateLocked(dump); @@ -3338,6 +3414,24 @@ void InputDispatcher::InputState::clear() { mMotionMementos.clear(); } +void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { + for (size_t i = 0; i < mMotionMementos.size(); i++) { + const MotionMemento& memento = mMotionMementos.itemAt(i); + if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { + for (size_t j = 0; j < other.mMotionMementos.size(); ) { + const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); + if (memento.deviceId == otherMemento.deviceId + && memento.source == otherMemento.source) { + other.mMotionMementos.removeAt(j); + } else { + j += 1; + } + } + other.mMotionMementos.push(memento); + } + } +} + bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource, CancelationOptions options) { switch (options) { diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 8345cc3..91e7df3 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -317,6 +317,12 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) mStringPoolSize = (mHeader->header.size-mHeader->stringsStart)/charSize; } else { + // check invariant: styles starts before end of data + if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) { + LOGW("Bad style block: style block starts at %d past data size of %d\n", + (int)mHeader->stylesStart, (int)mHeader->header.size); + return (mError=BAD_TYPE); + } // check invariant: styles follow the strings if (mHeader->stylesStart <= mHeader->stringsStart) { LOGW("Bad style block: style block starts at %d, before strings at %d\n", @@ -1878,6 +1884,12 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen); outName->name = grp->basePackage->keyStrings.stringAt( dtohl(entry->key.index), &outName->nameLen); + + // If we have a bad index for some reason, we should abort. + if (outName->type == NULL || outName->name == NULL) { + return false; + } + return true; } @@ -2609,6 +2621,24 @@ bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, *outType = *defType; } *outName = String16(p, end-p); + if(**outPackage == 0) { + if(outErrorMsg) { + *outErrorMsg = "Resource package cannot be an empty string"; + } + return false; + } + if(**outType == 0) { + if(outErrorMsg) { + *outErrorMsg = "Resource type cannot be an empty string"; + } + return false; + } + if(**outName == 0) { + if(outErrorMsg) { + *outErrorMsg = "Resource id cannot be an empty string"; + } + return false; + } return true; } @@ -4127,13 +4157,16 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; - this->getResourceName(resID, &resName); - printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", - resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - CHAR16_TO_CSTR(resName.type, resName.typeLen), - CHAR16_TO_CSTR(resName.name, resName.nameLen), - dtohl(typeConfigs->typeSpecFlags[entryIndex])); + if (this->getResourceName(resID, &resName)) { + printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", + resID, + CHAR16_TO_CSTR(resName.package, resName.packageLen), + CHAR16_TO_CSTR(resName.type, resName.typeLen), + CHAR16_TO_CSTR(resName.name, resName.nameLen), + dtohl(typeConfigs->typeSpecFlags[entryIndex])); + } else { + printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID); + } } } for (size_t configIndex=0; configIndex<NTC; configIndex++) { @@ -4340,11 +4373,14 @@ void ResTable::print(bool inclValues) const | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; - this->getResourceName(resID, &resName); - printf(" resource 0x%08x %s:%s/%s: ", resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - CHAR16_TO_CSTR(resName.type, resName.typeLen), - CHAR16_TO_CSTR(resName.name, resName.nameLen)); + if (this->getResourceName(resID, &resName)) { + printf(" resource 0x%08x %s:%s/%s: ", resID, + CHAR16_TO_CSTR(resName.package, resName.packageLen), + CHAR16_TO_CSTR(resName.type, resName.typeLen), + CHAR16_TO_CSTR(resName.name, resName.nameLen)); + } else { + printf(" INVALID RESOURCE 0x%08x: ", resID); + } if ((thisOffset&0x3) != 0) { printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset); continue; @@ -4402,18 +4438,19 @@ void ResTable::print(bool inclValues) const print_value(pkg, value); } else if (bagPtr != NULL) { const int N = dtohl(bagPtr->count); - const ResTable_map* mapPtr = (const ResTable_map*) - (((const uint8_t*)ent) + esize); + const uint8_t* baseMapPtr = (const uint8_t*)ent; + size_t mapOffset = esize; + const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); printf(" Parent=0x%08x, Count=%d\n", dtohl(bagPtr->parent.ident), N); - for (int i=0; i<N; i++) { + for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) { printf(" #%i (Key=0x%08x): ", i, dtohl(mapPtr->name.ident)); value.copyFrom_dtoh(mapPtr->value); print_value(pkg, value); const size_t size = dtohs(mapPtr->value.size); - mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr) - + size + sizeof(*mapPtr)-sizeof(mapPtr->value)); + mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value); + mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); } } } |