Add dithering to gradients

Change-Id: Ic1208855bde3a254eca2fd7cef43e0f1318ce419
This commit is contained in:
Romain Guy
2012-07-31 21:16:07 -07:00
parent 42e1e0d482
commit 211efea737
8 changed files with 187 additions and 19 deletions

View File

@@ -11,6 +11,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
Caches.cpp \
DisplayListLogBuffer.cpp \
DisplayListRenderer.cpp \
Dither.cpp \
FboCache.cpp \
GradientCache.cpp \
LayerCache.cpp \

View File

@@ -252,6 +252,7 @@ void Caches::flush(FlushMode mode) {
dropShadowCache.clear();
gradientCache.clear();
fontRenderer->clear();
dither.clear();
// fall through
case kFlushMode_Moderate:
fontRenderer->flush();

View File

@@ -38,6 +38,7 @@
#include "TextDropShadowCache.h"
#include "FboCache.h"
#include "ResourceCache.h"
#include "Dither.h"
namespace android {
namespace uirenderer {
@@ -250,6 +251,7 @@ public:
TextDropShadowCache dropShadowCache;
FboCache fboCache;
ResourceCache resourceCache;
Dither dither;
GammaFontRenderer* fontRenderer;

84
libs/hwui/Dither.cpp Executable file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2012 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 "Caches.h"
#include "Dither.h"
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////
// Must be a power of two
#define DITHER_KERNEL_SIZE 4
///////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////
void Dither::bindDitherTexture() {
if (!mInitialized) {
const uint8_t pattern[] = {
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
};
glGenTextures(1, &mDitherTexture);
glBindTexture(GL_TEXTURE_2D, mDitherTexture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
mInitialized = true;
} else {
glBindTexture(GL_TEXTURE_2D, mDitherTexture);
}
}
void Dither::clear() {
if (mInitialized) {
glDeleteTextures(1, &mDitherTexture);
}
}
///////////////////////////////////////////////////////////////////////////////
// Program management
///////////////////////////////////////////////////////////////////////////////
void Dither::setupProgram(Program* program, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
Caches::getInstance().activeTexture(textureSlot);
bindDitherTexture();
glUniform1i(program->getUniform("ditherSampler"), textureSlot);
glUniform1f(program->getUniform("ditherSize"), 1.0f / DITHER_KERNEL_SIZE);
}
}; // namespace uirenderer
}; // namespace android

47
libs/hwui/Dither.h Executable file
View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2012 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_DITHER_H
#define ANDROID_HWUI_DITHER_H
#include <GLES2/gl2.h>
#include "Program.h"
namespace android {
namespace uirenderer {
/**
* Handles dithering for programs.
*/
class Dither {
public:
Dither(): mInitialized(false), mDitherTexture(0) { }
void clear();
void setupProgram(Program* program, GLuint* textureUnit);
private:
void bindDitherTexture();
bool mInitialized;
GLuint mDitherTexture;
};
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_DITHER_H

View File

@@ -75,9 +75,11 @@ const char* gVS_Header_Varyings_HasGradient[6] = {
// Linear
"varying highp vec2 linear;\n",
"varying highp float linear;\n",
// Circular
"varying highp vec2 circular;\n",
"varying highp vec2 circular;\n",
// Sweep
"varying highp vec2 sweep;\n",
"varying highp vec2 sweep;\n",
@@ -92,9 +94,11 @@ const char* gVS_Main_OutGradient[6] = {
// Linear
" linear = vec2((screenSpace * position).x, 0.5);\n",
" linear = (screenSpace * position).x;\n",
// Circular
" circular = (screenSpace * position).xy;\n",
" circular = (screenSpace * position).xy;\n",
// Sweep
" sweep = (screenSpace * position).xy;\n",
" sweep = (screenSpace * position).xy;\n",
@@ -137,19 +141,24 @@ const char* gFS_Uniforms_TextureSampler =
"uniform sampler2D sampler;\n";
const char* gFS_Uniforms_ExternalTextureSampler =
"uniform samplerExternalOES sampler;\n";
#define FS_UNIFORMS_DITHER \
"uniform float ditherSize;\n" \
"uniform sampler2D ditherSampler;\n"
#define FS_UNIFORMS_GRADIENT \
"uniform vec4 startColor;\n" \
"uniform vec4 endColor;\n"
const char* gFS_Uniforms_GradientSampler[6] = {
// Linear
"uniform sampler2D gradientSampler;\n",
"uniform vec4 startColor;\n"
"uniform vec4 endColor;\n",
FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
// Circular
"uniform sampler2D gradientSampler;\n",
"uniform vec4 startColor;\n"
"uniform vec4 endColor;\n",
FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
// Sweep
"uniform sampler2D gradientSampler;\n",
"uniform vec4 startColor;\n"
"uniform vec4 endColor;\n",
FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT
};
const char* gFS_Uniforms_BitmapSampler =
"uniform sampler2D bitmapSampler;\n";
@@ -176,6 +185,11 @@ const char* gFS_Main_PointBitmapTexCoords =
" highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
"((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
#define FS_MAIN_DITHER \
"texture2D(ditherSampler, gl_FragCoord.xy * ditherSize).a * ditherSize * ditherSize"
const char* gFS_Main_AddDitherToGradient =
" gradientColor += " FS_MAIN_DITHER ";\n";
// Fast cases
const char* gFS_Fast_SingleColor =
"\nvoid main(void) {\n"
@@ -207,18 +221,18 @@ const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
"}\n\n";
const char* gFS_Fast_SingleGradient[2] = {
"\nvoid main(void) {\n"
" gl_FragColor = texture2D(gradientSampler, linear);\n"
" gl_FragColor = " FS_MAIN_DITHER " + texture2D(gradientSampler, linear);\n"
"}\n\n",
"\nvoid main(void) {\n"
" gl_FragColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
" gl_FragColor = " FS_MAIN_DITHER " + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
"}\n\n"
};
const char* gFS_Fast_SingleModulateGradient[2] = {
"\nvoid main(void) {\n"
" gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
" gl_FragColor " FS_MAIN_DITHER " + color.a * texture2D(gradientSampler, linear);\n"
"}\n\n",
"\nvoid main(void) {\n"
" gl_FragColor = color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
" gl_FragColor " FS_MAIN_DITHER " + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
"}\n\n"
};
@@ -254,16 +268,21 @@ const char* gFS_Main_FetchA8Texture[2] = {
};
const char* gFS_Main_FetchGradient[6] = {
// Linear
" vec4 gradientColor = texture2D(gradientSampler, linear);\n",
" vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
" highp vec4 gradientColor = texture2D(gradientSampler, linear);\n",
" highp vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
// Circular
" vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
" vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
" highp vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
" highp vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
// Sweep
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
" highp vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
@@ -651,6 +670,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
}
if (description.hasGradient) {
shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
shader.append(gFS_Main_AddDitherToGradient);
}
if (description.hasBitmap) {
if (description.isPoint) {

View File

@@ -250,6 +250,8 @@ void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelV
bindUniformColor(program->getUniform("endColor"), mColors[1]);
}
Caches::getInstance().dither.setupProgram(program, textureUnit);
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
@@ -375,6 +377,8 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi
bindUniformColor(program->getUniform("endColor"), mColors[1]);
}
Caches::getInstance().dither.setupProgram(program, textureUnit);
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, modelView);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);

View File

@@ -19,6 +19,7 @@ package com.android.test.hwui;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
@@ -111,6 +112,14 @@ public class GradientStopsActivity extends Activity {
canvas.translate(0.0f, 75.0f);
canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
gradient = new LinearGradient(0.0f, 0.0f, 512.0f, 0.0f,
colors, null, Shader.TileMode.CLAMP);
paint.setShader(gradient);
canvas.translate(0.0f, 75.0f);
canvas.drawRect(0.0f, 0.0f, 512.0f, 50.0f, paint);
}
}
}