/*
* Copyright (C) 2010 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_PROGRAM_CACHE_H
#define ANDROID_HWUI_PROGRAM_CACHE_H
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <GLES2/gl2.h>
#include <SkXfermode.h>
#include "Debug.h"
#include "Program.h"
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////
// Debug
#if DEBUG_PROGRAMS
#define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
#else
#define PROGRAM_LOGD(...)
#endif
// TODO: This should be set in properties
#define PANEL_BIT_DEPTH 20
#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
#define PROGRAM_KEY_TEXTURE 0x1
#define PROGRAM_KEY_A8_TEXTURE 0x2
#define PROGRAM_KEY_BITMAP 0x4
#define PROGRAM_KEY_GRADIENT 0x8
#define PROGRAM_KEY_BITMAP_FIRST 0x10
#define PROGRAM_KEY_COLOR_MATRIX 0x20
#define PROGRAM_KEY_COLOR_LIGHTING 0x40
#define PROGRAM_KEY_COLOR_BLEND 0x80
#define PROGRAM_KEY_BITMAP_NPOT 0x100
#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
// Encode the xfermodes on 6 bits
#define PROGRAM_MAX_XFERMODE 0x1f
#define PROGRAM_XFERMODE_SHADER_SHIFT 26
#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
#define PROGRAM_BITMAP_WRAPS_SHIFT 9
#define PROGRAM_BITMAP_WRAPT_SHIFT 11
#define PROGRAM_GRADIENT_TYPE_SHIFT 33
#define PROGRAM_MODULATE_SHIFT 35
#define PROGRAM_IS_POINT_SHIFT 36
#define PROGRAM_HAS_AA_SHIFT 37
#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
typedef uint64_t programid;
///////////////////////////////////////////////////////////////////////////////
// Cache
///////////////////////////////////////////////////////////////////////////////
/**
* Describe the features required for a given program. The features
* determine the generation of both the vertex and fragment shaders.
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
enum ColorModifier {
kColorNone,
kColorMatrix,
kColorLighting,
kColorBlend
};
enum Gradient {
kGradientLinear,
kGradientCircular,
kGradientSweep
};
ProgramDescription() {
reset();
}
// Texturing
bool hasTexture;
bool hasAlpha8Texture;
bool hasExternalTexture;
bool hasTextureTransform;
// Modulate, this should only be set when setColor() return true
bool modulate;
// Shaders
bool hasBitmap;
bool isBitmapNpot;
bool isAA;
bool hasGradient;
Gradient gradientType;
SkXfermode::Mode shadersMode;
bool isBitmapFirst;
GLenum bitmapWrapS;
GLenum bitmapWrapT;
// Color operations
ColorModifier colorOp;
SkXfermode::Mode colorMode;
// Framebuffer blending (requires Extensions.hasFramebufferFetch())
// Ignored for all values < SkXfermode::kPlus_Mode
SkXfermode::Mode framebufferMode;
bool swapSrcDst;
bool isPoint;
float pointSize;
/**
* Resets this description. All fields are reset back to the default
* values they hold after building a new instance.
*/
void reset() {
hasTexture = false;
hasAlpha8Texture = false;
hasExternalTexture = false;
hasTextureTransform = false;
isAA = false;
modulate = false;
hasBitmap = false;
isBitmapNpot = false;
hasGradient = false;
gradientType = kGradientLinear;
shadersMode = SkXfermode::kClear_Mode;
isBitmapFirst = false;
bitmapWrapS = GL_CLAMP_TO_EDGE;
bitmapWrapT = GL_CLAMP_TO_EDGE;
colorOp = kColorNone;
colorMode = SkXfermode::kClear_Mode;
framebufferMode = SkXfermode::kClear_Mode;
swapSrcDst = false;
isPoint = false;
pointSize = 0.0f;
}
/**
* Indicates, for a given color, whether color modulation is required in
* the fragment shader. When this method returns true, the program should
* be provided with a modulation color.
*/
bool setColor(const float r, const float g, const float b, const float a) {
modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
return modulate;
}
/**
* Indicates, for a given color, whether color modulation is required in
* the fragment shader. When this method returns true, the program should
* be provided with a modulation color.
*/
bool setAlpha8Color(const float r, const float g, const float b, const float a) {
modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
return modulate;
}
/**
* Computes the unique key identifying this program.
*/
programid key() const {
programid key = 0;
if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
if (hasBitmap) {
key |= PROGRAM_KEY_BITMAP;
if (isBitmapNpot) {
key |= PROGRAM_KEY_BITMAP_NPOT;
key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
}
}
if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
if (hasBitmap && hasGradient) {
key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
}
switch (colorOp) {
case kColorMatrix:
key |= PROGRAM_KEY_COLOR_MATRIX;
break;
case kColorLighting:
key |= PROGRAM_KEY_COLOR_LIGHTING;
break;
case kColorBlend:
key |= PROGRAM_KEY_COLOR_BLEND;
key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
break;
case kColorNone:
break;
}
key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
return key;
}
/**
* Logs the specified message followed by the key identifying this program.
*/
void log(const char* message) const {
#if DEBUG_PROGRAMS
programid k = key();
PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
uint32_t(k & 0xffffffff));
#endif
}
private:
inline uint32_t getEnumForWrap(GLenum wrap) const {
switch (wrap) {
case GL_CLAMP_TO_EDGE:
return 0;
case GL_REPEAT:
return 1;
case GL_MIRRORED_REPEAT:
return 2;
}
return 0;
}
}; // struct ProgramDescription
/**
* Generates and caches program. Programs are generated based on
* ProgramDescriptions.
*/
class ProgramCache {
public:
ProgramCache();
~ProgramCache();
Program* get(const ProgramDescription& description);
void clear();
private:
Program* generateProgram(const ProgramDescription& description, programid key);
String8 generateVertexShader(const ProgramDescription& description);
String8 generateFragmentShader(const ProgramDescription& description);
void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
void printLongString(const String8& shader) const;
KeyedVector<programid, Program*> mCache;
}; // class ProgramCache
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_PROGRAM_CACHE_H