Use LUT for computing final shadow alpha
bug:27415250
Significantly reduces shadow fragment shader computation.
Change-Id: Ie9b3c712700754b3734d0ae9cda8751c298fc59e
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index ea4391b..e78cd72 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -298,7 +298,8 @@
// indices
meshState().bindIndicesBuffer(indices.bufferObject);
- if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
+ // texture
+ if (fill.texture.texture != nullptr) {
const Glop::Fill::TextureData& texture = fill.texture;
// texture always takes slot 0, shader samplers increment from there
mCaches->textureState().activateTexture(0);
@@ -311,13 +312,16 @@
texture.texture->setFilter(texture.filter, false, false, texture.target);
}
- meshState().enableTexCoordsVertexArray();
- meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
-
if (texture.textureTransform) {
glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
GL_FALSE, &texture.textureTransform->data[0]);
}
+ }
+
+ // vertex attributes (tex coord, color, alpha)
+ if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
+ meshState().enableTexCoordsVertexArray();
+ meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
} else {
meshState().disableTexCoordsVertexArray();
}
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 78b8eda..f9a1f8c 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -26,6 +26,9 @@
namespace android {
namespace uirenderer {
+// Width of mShadowLutTexture, defines how accurate the shadow alpha lookup table is
+static const int SHADOW_LUT_SIZE = 128;
+
// Must define as many texture units as specified by kTextureUnitsCount
const GLenum kTextureUnits[] = {
GL_TEXTURE0,
@@ -46,6 +49,41 @@
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
+TextureState::~TextureState() {
+ if (mShadowLutTexture != nullptr) {
+ mShadowLutTexture->deleteTexture();
+ }
+}
+
+/**
+ * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to
+ * darkness at that spot. Input values of 0->1 should be mapped within the same
+ * range, but can affect the curve for a different visual falloff.
+ *
+ * This is used to populate the shadow LUT texture for quick lookup in the
+ * shadow shader.
+ */
+static float computeShadowOpacity(float ratio) {
+ // exponential falloff function provided by UX
+ float val = 1 - ratio;
+ return exp(-val * val * 4.0) - 0.018;
+}
+
+void TextureState::constructTexture(Caches& caches) {
+ if (mShadowLutTexture == nullptr) {
+ mShadowLutTexture.reset(new Texture(caches));
+
+ unsigned char bytes[SHADOW_LUT_SIZE];
+ for (int i = 0; i < SHADOW_LUT_SIZE; i++) {
+ float inputRatio = i / (SHADOW_LUT_SIZE - 1.0f);
+ bytes[i] = computeShadowOpacity(inputRatio) * 255;
+ }
+ mShadowLutTexture->upload(GL_ALPHA, SHADOW_LUT_SIZE, 1, GL_ALPHA, GL_UNSIGNED_BYTE, &bytes);
+ mShadowLutTexture->setFilter(GL_LINEAR);
+ mShadowLutTexture->setWrap(GL_CLAMP_TO_EDGE);
+ }
+}
+
void TextureState::activateTexture(GLuint textureUnit) {
LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount,
"Tried to use texture unit index %d, only %d exist",
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index ec94d7e..7296fd3 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -17,14 +17,12 @@
#define RENDERSTATE_TEXTURESTATE_H
#include "Vertex.h"
+#include "Texture.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-#include <SkXfermode.h>
#include <memory>
-class SkBitmap;
-
namespace android {
namespace uirenderer {
@@ -33,6 +31,9 @@
class TextureState {
friend class Caches; // TODO: move to RenderState
public:
+
+ void constructTexture(Caches& caches);
+
/**
* Activate the specified texture unit. The texture unit must
* be specified using an integer number (0 for GL_TEXTURE0 etc.)
@@ -76,15 +77,20 @@
*/
void unbindTexture(GLuint texture);
+ Texture* getShadowLutTexture() { return mShadowLutTexture.get(); }
+
private:
// total number of texture units available for use
static const int kTextureUnitsCount = 4;
TextureState();
+ ~TextureState();
GLuint mTextureUnit;
// Caches texture bindings for the GL_TEXTURE_2D target
GLuint mBoundTextures[kTextureUnitsCount];
+
+ std::unique_ptr<Texture> mShadowLutTexture;
};
} /* namespace uirenderer */