Merge "Revert "Revert "Use RenderScript for large text blurs"""
This commit is contained in:
@ -38,6 +38,8 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
|||||||
TextureCache.cpp \
|
TextureCache.cpp \
|
||||||
TextDropShadowCache.cpp
|
TextDropShadowCache.cpp
|
||||||
|
|
||||||
|
intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += \
|
LOCAL_C_INCLUDES += \
|
||||||
$(JNI_H_INCLUDE) \
|
$(JNI_H_INCLUDE) \
|
||||||
$(LOCAL_PATH)/../../include/utils \
|
$(LOCAL_PATH)/../../include/utils \
|
||||||
@ -45,11 +47,14 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
|||||||
external/skia/include/effects \
|
external/skia/include/effects \
|
||||||
external/skia/include/images \
|
external/skia/include/images \
|
||||||
external/skia/src/ports \
|
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_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
|
||||||
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
|
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 := libhwui
|
||||||
LOCAL_MODULE_TAGS := optional
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
@ -63,5 +68,5 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
|||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||||
endif
|
endif
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include "RenderScript.h"
|
||||||
|
|
||||||
|
#include "utils/Timing.h"
|
||||||
#include "Caches.h"
|
#include "Caches.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "FontRenderer.h"
|
#include "FontRenderer.h"
|
||||||
@ -30,6 +33,9 @@
|
|||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
|
|
||||||
|
// blur inputs smaller than this constant will bypass renderscript
|
||||||
|
#define RS_MIN_INPUT_CUTOFF 10000
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// FontRenderer
|
// FontRenderer
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -543,18 +549,22 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
|
|||||||
|
|
||||||
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
|
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
|
||||||
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 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++) {
|
// Align buffers for renderscript usage
|
||||||
dataBuffer[i] = 0;
|
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 penX = radius - bounds.left;
|
||||||
int penY = radius - bounds.bottom;
|
int penY = radius - bounds.bottom;
|
||||||
|
|
||||||
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
|
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
|
||||||
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
|
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
|
||||||
blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
|
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
|
||||||
|
|
||||||
DropShadow image;
|
DropShadow image;
|
||||||
image.width = paddedWidth;
|
image.width = paddedWidth;
|
||||||
@ -751,18 +761,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) {
|
uint8_t* scratch = new uint8_t[width * height];
|
||||||
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);
|
||||||
|
|
||||||
horizontalBlur(gaussian, radius, image, scratch, width, height);
|
delete[] gaussian;
|
||||||
verticalBlur(gaussian, radius, scratch, image, width, height);
|
delete[] scratch;
|
||||||
|
}
|
||||||
|
|
||||||
delete[] gaussian;
|
uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
|
||||||
delete[] scratch;
|
|
||||||
|
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
|
}; // namespace uirenderer
|
||||||
|
@ -31,6 +31,12 @@
|
|||||||
#include "Matrix.h"
|
#include "Matrix.h"
|
||||||
#include "Properties.h"
|
#include "Properties.h"
|
||||||
|
|
||||||
|
namespace RSC {
|
||||||
|
class Element;
|
||||||
|
class RS;
|
||||||
|
class ScriptIntrinsicBlur;
|
||||||
|
}
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
|
|
||||||
@ -178,13 +184,19 @@ private:
|
|||||||
Vector<uint32_t> mDrawCounts;
|
Vector<uint32_t> mDrawCounts;
|
||||||
Vector<CacheTexture*> mDrawCacheTextures;
|
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 computeGaussianWeights(float* weights, int32_t radius);
|
||||||
static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
||||||
int32_t width, int32_t height);
|
int32_t width, int32_t height);
|
||||||
static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
||||||
int32_t width, int32_t height);
|
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
|
}; // namespace uirenderer
|
||||||
|
@ -222,7 +222,7 @@ ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup shadow
|
// Cleanup shadow
|
||||||
delete[] shadow.image;
|
delete shadow.image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture;
|
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