Use RenderScript for large text blurs

Still fall back to simple path for small tasks

Change-Id: I492f1b3f7d6fec1738f3e45cbfb15864bd23a392
This commit is contained in:
Chris Craik
2012-11-14 16:11:10 -08:00
parent d04892d207
commit 3f76e65d25
5 changed files with 113 additions and 18 deletions

View File

@ -37,6 +37,8 @@ ifeq ($(USE_OPENGL_RENDERER),true)
TextureCache.cpp \
TextDropShadowCache.cpp
intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(LOCAL_PATH)/../../include/utils \
@ -45,11 +47,14 @@ ifeq ($(USE_OPENGL_RENDERER),true)
external/skia/include/images \
external/skia/src/core \
external/skia/src/ports \
external/skia/include/utils
external/skia/include/utils \
$(intermediates) \
frameworks/rs/cpp \
frameworks/rs
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui libRS libRScpp
LOCAL_MODULE := libhwui
LOCAL_MODULE_TAGS := optional
@ -63,5 +68,5 @@ ifeq ($(USE_OPENGL_RENDERER),true)
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
include $(call all-makefiles-under,$(LOCAL_PATH))
endif

View File

@ -23,6 +23,9 @@
#include <utils/Log.h>
#include "RenderScript.h"
#include "utils/Timing.h"
#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
@ -31,6 +34,9 @@
namespace android {
namespace uirenderer {
// blur inputs smaller than this constant will bypass renderscript
#define RS_MIN_INPUT_CUTOFF 10000
///////////////////////////////////////////////////////////////////////////////
// FontRenderer
///////////////////////////////////////////////////////////////////////////////
@ -544,18 +550,22 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
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;
// Align buffers for renderscript usage
if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
}
int size = paddedWidth * paddedHeight;
uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
memset(dataBuffer, 0, size);
int penX = radius - bounds.left;
int penY = radius - bounds.bottom;
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
DropShadow image;
image.width = paddedWidth;
@ -752,18 +762,44 @@ void FontRenderer::verticalBlur(float* weights, int32_t radius,
}
}
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
if (width * height * radius < RS_MIN_INPUT_CUTOFF) {
float *gaussian = new float[2 * radius + 1];
computeGaussianWeights(gaussian, radius);
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];
uint8_t* scratch = new uint8_t[width * height];
horizontalBlur(gaussian, radius, *image, scratch, width, height);
verticalBlur(gaussian, radius, scratch, *image, width, height);
horizontalBlur(gaussian, radius, image, scratch, width, height);
verticalBlur(gaussian, radius, scratch, image, width, height);
delete[] gaussian;
delete[] scratch;
}
delete[] gaussian;
delete[] scratch;
uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
if (mRs.get() == 0) {
mRs = new RSC::RS();
if (!mRs->init(true, true)) {
ALOGE("blur RS failed to init");
}
mRsElement = RSC::Element::A_8(mRs);
mRsScript = new RSC::ScriptIntrinsicBlur(mRs, mRsElement);
}
sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
mRsScript->setRadius(radius);
mRsScript->blur(ain, aout);
// replace the original image's pointer, avoiding a copy back to the original buffer
delete *image;
*image = outImage;
}
}; // namespace uirenderer

View File

@ -31,6 +31,12 @@
#include "Matrix.h"
#include "Properties.h"
namespace RSC {
class Element;
class RS;
class ScriptIntrinsicBlur;
}
namespace android {
namespace uirenderer {
@ -178,13 +184,19 @@ private:
Vector<uint32_t> mDrawCounts;
Vector<CacheTexture*> mDrawCacheTextures;
/** We should consider multi-threading this code or using Renderscript **/
// RS constructs
sp<RSC::RS> mRs;
sp<const RSC::Element> mRsElement;
sp<RSC::ScriptIntrinsicBlur> mRsScript;
static void computeGaussianWeights(float* weights, int32_t radius);
static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
int32_t width, int32_t height);
static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
int32_t width, int32_t height);
static void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius);
// the input image handle may have its pointer replaced (to avoid copies)
void blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius);
};
}; // namespace uirenderer

View File

@ -222,7 +222,7 @@ ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32
}
// Cleanup shadow
delete[] shadow.image;
delete shadow.image;
}
return texture;

42
libs/hwui/utils/Timing.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HWUI_TIMING_H
#define ANDROID_HWUI_TIMING_H
#include <sys/time.h>
#define TIME_METHOD() MethodTimer __method_timer(__func__)
class MethodTimer {
public:
MethodTimer(const char* name)
: mMethodName(name) {
gettimeofday(&mStart, NULL);
}
~MethodTimer() {
struct timeval stop;
gettimeofday(&stop, NULL);
long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
+ (stop.tv_usec - mStart.tv_usec);
ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);
}
private:
const char* mMethodName;
struct timeval mStart;
};
#endif