Use RenderScript for large text blurs
Still fall back to simple path for small tasks Change-Id: I492f1b3f7d6fec1738f3e45cbfb15864bd23a392
This commit is contained in:
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
42
libs/hwui/utils/Timing.h
Normal 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
|
Reference in New Issue
Block a user