/* libs/graphics/sgl/SkGraphics.cpp
**
** Copyright 2006, 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 "SkGraphics.h"
#include "Sk64.h"
#include "SkBlitter.h"
#include "SkCanvas.h"
#include "SkFloat.h"
#include "SkGeometry.h"
#include "SkGlobals.h"
#include "SkMath.h"
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPathEffect.h"
#include "SkRandom.h"
#include "SkRefCnt.h"
#include "SkScalerContext.h"
#include "SkShader.h"
#include "SkStream.h"
#include "SkTSearch.h"
#include "SkTime.h"
#include "SkUtils.h"
#include "SkXfermode.h"
#if 0
#define SK_SORT_TEMPLATE_TYPE int
#define SK_SORT_TEMPLATE_NAME sort_int
#define SK_SORT_TEMPLATE_CMP(a, b) ((a) - (b))
#include "SkSortTemplate.h"
#define SK_SORT_TEMPLATE_TYPE int*
#define SK_SORT_TEMPLATE_NAME sort_intptr
#define SK_SORT_TEMPLATE_CMP(a, b) (*(a) - *(b))
#include "SkSortTemplate.h"
static void test_sort()
{
int array[] = { 4, 3, 7, 5, 2, 5, 1, 2, 9, 6, 7, 4, 5, 3, 1, 0 };
int* ptr[SK_ARRAY_COUNT(array)];
int i, N = SK_ARRAY_COUNT(array) - 1;
for (i = 0; i < N; i++)
printf(" %d", array[i]);
printf("\n");
for (i = 0; i < N; i++)
ptr[i] = &array[i];
sort_intptr(ptr, N);
for (i = 0; i < N; i++)
printf(" %d", *ptr[i]);
printf("\n");
sort_int(array, N);
for (i = 0; i < N; i++)
printf(" %d", array[i]);
printf("\n");
}
#endif
#define SPEED_TESTx
#define typesizeline(type) { #type , sizeof(type) }
#ifdef BUILD_EMBOSS_TABLE
extern void SkEmbossMask_BuildTable();
#endif
#ifdef BUILD_RADIALGRADIENT_TABLE
extern void SkRadialGradient_BuildTable();
#endif
#define BIG_LOOP_COUNT 1000000
#define TEXT_LOOP_COUNT 1000
#ifdef SPEED_TEST
static int test_s64(int i)
{
Sk64 a, b, c;
c.set(0);
a.set(i);
b.setMul(i, i);
a.add(b);
a.add(c);
return c.getFixed();
}
static int test_native_64(int i)
{
int16_t a, b, c;
c = 0;
a = i;
b = (int64_t)i * i;
a += b;
a += c;
return (int)(c >> 16);
}
static void test_drawText(SkBitmap::Config config, SkColor color)
{
SkBitmap bm;
bm.setConfig(config, 320, 240);
bm.allocPixels();
SkCanvas canvas(bm);
SkPaint paint;
paint.setAntiAlias(true);
paint.setTextSize(SkIntToScalar(12));
paint.setColor(color);
SkScalar x = SkIntToScalar(20);
SkScalar y = SkIntToScalar(100);
const char* text = "Hamburgefons";
size_t len = strlen(text);
// draw once to populate the cache
canvas.drawText(text, len, x, y, paint);
SkMSec now = SkTime::GetMSecs();
for (int i = 0; i < TEXT_LOOP_COUNT; i++)
canvas.drawText(text, len, x, y, paint);
printf("----------- Config: %d, Color=%x, CPS = %g\n", config, color,
len * TEXT_LOOP_COUNT * 1000.0 / (SkTime::GetMSecs() - now));
}
#endif
#ifdef SK_CAN_USE_FLOAT
#include "SkFloatBits.h"
static inline float fast_inc(float x) {
SkFloatIntUnion data;
data.fFloat = x;
data.fSignBitInt += 1;
return data.fFloat;
}
extern float dummy();
int time_math() {
SkMSec now;
int i;
int sum = 0;
const int repeat = 1000000;
float f;
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += (int)f; f = fast_inc(f);
sum += (int)f; f = fast_inc(f);
sum += (int)f; f = fast_inc(f);
sum += (int)f; f = fast_inc(f);
}
SkDebugf("---- native cast %d\n", SkTime::GetMSecs() - now);
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkFloatToIntCast(f); f = fast_inc(f);
sum += SkFloatToIntCast(f); f = fast_inc(f);
sum += SkFloatToIntCast(f); f = fast_inc(f);
sum += SkFloatToIntCast(f); f = fast_inc(f);
}
SkDebugf("---- hack cast %d\n", SkTime::GetMSecs() - now);
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += (int)floorf(f + 0.5f); f = fast_inc(f);
sum += (int)floorf(f + 0.5f); f = fast_inc(f);
sum += (int)floorf(f + 0.5f); f = fast_inc(f);
sum += (int)floorf(f + 0.5f); f = fast_inc(f);
}
SkDebugf("---- native round %d\n", SkTime::GetMSecs() - now);
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkFloatToIntRound(f); f = fast_inc(f);
sum += SkFloatToIntRound(f); f = fast_inc(f);
sum += SkFloatToIntRound(f); f = fast_inc(f);
sum += SkFloatToIntRound(f); f = fast_inc(f);
}
SkDebugf("---- hack round %d\n", SkTime::GetMSecs() - now);
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkFloat2Bits(floorf(f)); f = fast_inc(f);
sum += SkFloat2Bits(floorf(f)); f = fast_inc(f);
sum += SkFloat2Bits(floorf(f)); f = fast_inc(f);
sum += SkFloat2Bits(floorf(f)); f = fast_inc(f);
}
SkDebugf("---- native floor %d\n", SkTime::GetMSecs() - now);
f = dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkFloatToIntFloor(f); f = fast_inc(f);
sum += SkFloatToIntFloor(f); f = fast_inc(f);
sum += SkFloatToIntFloor(f); f = fast_inc(f);
sum += SkFloatToIntFloor(f); f = fast_inc(f);
}
SkDebugf("---- hack floor %d\n", SkTime::GetMSecs() - now);
return sum;
}
#if 0
static float time_intToFloat() {
const int repeat = 1000000;
int i, n;
SkMSec now;
float sum = 0;
n = (int)dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += (float)n; n += 1;
sum += (float)n; n += 1;
sum += (float)n; n += 1;
sum += (float)n; n += 1;
}
SkDebugf("---- native i2f %d\n", SkTime::GetMSecs() - now);
n = (int)dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkIntToFloatCast(n); n += 1;
sum += SkIntToFloatCast(n); n += 1;
sum += SkIntToFloatCast(n); n += 1;
sum += SkIntToFloatCast(n); n += 1;
}
SkDebugf("---- check i2f %d\n", SkTime::GetMSecs() - now);
n = (int)dummy();
now = SkTime::GetMSecs();
for (i = repeat - 1; i >= 0; --i) {
sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1;
sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1;
sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1;
sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1;
}
SkDebugf("---- nocheck i2f %d\n", SkTime::GetMSecs() - now);
return sum;
}
#endif
#endif
void SkGraphics::Init()
{
SkGlobals::Init();
#ifdef SK_CAN_USE_FLOAT
// time_math();
// time_intToFloat();
#endif
#ifdef BUILD_EMBOSS_TABLE
SkEmbossMask_BuildTable();
#endif
#ifdef BUILD_RADIALGRADIENT_TABLE
SkRadialGradient_BuildTable();
#endif
#ifdef SK_DEBUGx
int i;
static const struct {
const char* fTypeName;
size_t fSizeOf;
} gTypeSize[] = {
typesizeline(char),
typesizeline(short),
typesizeline(int),
typesizeline(long),
typesizeline(size_t),
typesizeline(void*),
typesizeline(S8CPU),
typesizeline(U8CPU),
typesizeline(S16CPU),
typesizeline(U16CPU),
typesizeline(SkPoint),
typesizeline(SkRect),
typesizeline(SkMatrix),
typesizeline(SkPath),
typesizeline(SkGlyph),
typesizeline(SkRefCnt),
typesizeline(SkPaint),
typesizeline(SkCanvas),
typesizeline(SkBlitter),
typesizeline(SkShader),
typesizeline(SkXfermode),
typesizeline(SkPathEffect)
};
#ifdef SK_CPU_BENDIAN
SkDebugf("SkGraphics: big-endian\n");
#else
SkDebugf("SkGraphics: little-endian\n");
#endif
{
char test = 0xFF;
int itest = test; // promote to int, see if it sign-extended
if (itest < 0)
SkDebugf("SkGraphics: char is signed\n");
else
SkDebugf("SkGraphics: char is unsigned\n");
}
for (i = 0; i < (int)SK_ARRAY_COUNT(gTypeSize); i++) {
SkDebugf("SkGraphics: sizeof(%s) = %d\n",
gTypeSize[i].fTypeName, gTypeSize[i].fSizeOf);
}
#endif
if (false) // test asm fixmul
{
int j;
SkMSec now = SkTime::GetMSecs();
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkFixedMul_portable(0x8000, 0x150000);
}
SkMSec now2 = SkTime::GetMSecs();
printf("-------- SkFixedMul_portable = %d\n", now2 - now);
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkFixedMul(0x8000, 0x150000);
}
printf("-------- SkFixedMul = %d\n", SkTime::GetMSecs() - now2);
SkRandom rand;
for (j = 0; j < 10000; j++) {
SkFixed a = rand.nextS() >> 8;
SkFixed b = rand.nextS() >> 8;
SkFixed c1 = SkFixedMul_portable(a, b);
SkFixed c2 = SkFixedMul(a, b);
if (SkAbs32(c1 - c2) > 1)
printf("------ FixMul disagreement: (%x %x) slow=%x fast=%x\n", a, b, c1, c2);
}
}
if (false) // test asm fractmul
{
int j;
SkMSec now = SkTime::GetMSecs();
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkFractMul_portable(0x800000, 0x1500000);
}
SkMSec now2 = SkTime::GetMSecs();
printf("-------- SkFractMul_portable = %d\n", now2 - now);
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkFractMul(0x800000, 0x1500000);
}
printf("-------- SkFractMul = %d\n", SkTime::GetMSecs() - now2);
SkRandom rand;
for (j = 0; j < 10000; j++) {
SkFixed a = rand.nextS() >> 1;
SkFixed b = rand.nextS() >> 1;
SkFixed c1 = SkFractMul_portable(a, b);
SkFixed c2 = SkFractMul(a, b);
if (SkAbs32(c1 - c2) > 1)
printf("------ FractMul disagreement: (%x %x) slow=%x fast=%x\n", a, b, c1, c2);
}
}
if (false) // test asm clz
{
int j;
SkMSec now = SkTime::GetMSecs();
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkCLZ_portable(now);
}
SkMSec now2 = SkTime::GetMSecs();
printf("-------- SkCLZ_portable = %d\n", now2 - now);
for (j = 0; j < BIG_LOOP_COUNT; j++) {
(void)SkCLZ(now);
}
printf("-------- SkCLZ = %d\n", SkTime::GetMSecs() - now2);
SkRandom rand;
for (j = 0; j < 10000; j++) {
uint32_t a = rand.nextU();
int c1 = SkCLZ_portable(a);
int c2 = SkCLZ(a);
if (c1 != c2)
printf("------ CLZ disagreement: (%x) slow=%x fast=%x\n", a, c1, c2);
}
}
#ifdef SPEED_TEST
if (false) {
int i;
int (*proc)(int);
static const struct {
int (*proc)(int);
const char* name;
} gList[] = {
{ test_s64, "Sk64" },
{ test_native_64, "native" }
};
for (size_t j = 0; j < SK_ARRAY_COUNT(gList); j++) {
SkMSec now = SkTime::GetMSecs();
proc = gList[j].proc;
for (i = 0; i < BIG_LOOP_COUNT; i++) {
proc(i);
}
printf("-------- %s = %d\n", gList[j].name, SkTime::GetMSecs() - now);
}
}
#endif
if (false) {
size_t i, size = 480;
char* buffer = (char*)sk_malloc_throw(size);
uint16_t* buffer16 = (uint16_t*)buffer;
uint32_t* buffer32 = (uint32_t*)buffer;
SkMSec now = SkTime::GetMSecs();
for (i = 0; i < 100000; i++) {
sk_memset16(buffer16, (uint16_t)i, size >> 1);
}
SkMSec now2 = SkTime::GetMSecs();
for (i = 0; i < 100000; i++) {
sk_memset16_portable(buffer16, (uint16_t)i, size >> 1);
}
SkMSec now3 = SkTime::GetMSecs();
printf("----------- memset16: native %d, portable %d\n", now2 - now, now3 - now2);
now = SkTime::GetMSecs();
for (i = 0; i < 100000; i++) {
sk_memset32(buffer32, i, size >> 2);
}
now2 = SkTime::GetMSecs();
for (i = 0; i < 100000; i++) {
sk_memset32_portable(buffer32, i, size >> 2);
}
now3 = SkTime::GetMSecs();
printf("----------- memset32: native %d, portable %d\n", now2 - now, now3 - now2);
sk_free(buffer);
}
#ifdef SPEED_TEST
if (false) {
test_drawText(SkBitmap::kARGB_8888_Config, SK_ColorBLACK);
test_drawText(SkBitmap::kARGB_8888_Config, SK_ColorRED);
test_drawText(SkBitmap::kRGB_565_Config, SK_ColorBLACK);
test_drawText(SkBitmap::kRGB_565_Config, SK_ColorRED);
}
#endif
// if (true) {
// test_sort();
// }
}
////////////////////////////////////////////////////////////////////////////
#include "SkGlyphCache.h"
void SkGraphics::Term() {
SkGraphics::SetFontCacheUsed(0);
SkGlobals::Term();
}
size_t SkGraphics::GetFontCacheUsed() {
return SkGlyphCache::GetCacheUsed();
}
bool SkGraphics::SetFontCacheUsed(size_t usageInBytes) {
return SkGlyphCache::SetCacheUsed(usageInBytes);
}
float dummy() { return 1.25f; }