Add dithering to gradients
Change-Id: Ic1208855bde3a254eca2fd7cef43e0f1318ce419
This commit is contained in:
@@ -11,6 +11,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
Caches.cpp \
|
||||
DisplayListLogBuffer.cpp \
|
||||
DisplayListRenderer.cpp \
|
||||
Dither.cpp \
|
||||
FboCache.cpp \
|
||||
GradientCache.cpp \
|
||||
LayerCache.cpp \
|
||||
|
||||
@@ -252,6 +252,7 @@ void Caches::flush(FlushMode mode) {
|
||||
dropShadowCache.clear();
|
||||
gradientCache.clear();
|
||||
fontRenderer->clear();
|
||||
dither.clear();
|
||||
// fall through
|
||||
case kFlushMode_Moderate:
|
||||
fontRenderer->flush();
|
||||
|
||||
@@ -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
84
libs/hwui/Dither.cpp
Executable 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
47
libs/hwui/Dither.h
Executable 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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user