summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/FontRenderer.cpp1
-rw-r--r--libs/hwui/Matrix.cpp5
-rw-r--r--libs/hwui/OpenGLRenderer.cpp194
-rw-r--r--libs/hwui/OpenGLRenderer.h28
-rw-r--r--libs/hwui/Program.cpp125
-rw-r--r--libs/hwui/Program.h165
-rw-r--r--libs/hwui/ProgramCache.cpp67
-rw-r--r--libs/hwui/ProgramCache.h40
-rw-r--r--libs/hwui/shaders/drawColor.frag11
-rw-r--r--libs/hwui/shaders/drawLinearGradient.frag14
-rw-r--r--libs/hwui/shaders/drawLinearGradient.vert20
-rw-r--r--libs/hwui/shaders/drawText.frag14
-rw-r--r--libs/hwui/shaders/drawTexture.frag14
-rw-r--r--libs/hwui/shaders/drawTexture.vert15
14 files changed, 277 insertions, 436 deletions
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5595ab0..6074ec8 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -327,6 +327,7 @@ void FontRenderer::initTextTexture() {
mTextTexture = new unsigned char[mCacheWidth * mCacheHeight];
mUploadTexture = false;
+ glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &mTextureId);
glBindTexture(GL_TEXTURE_2D, mTextureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index b459202..0c31ba9 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -152,6 +152,11 @@ void Matrix4::loadRotate(float angle, float x, float y, float z) {
float s = sinf(angle);
const float length = sqrtf(x * x + y * y + z * z);
+ float recipLen = 1.0f / length;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+
const float nc = 1.0f - c;
const float xy = x * y;
const float yz = y * z;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 0ed6276..3d9aa26 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -62,6 +62,15 @@ static const TextureVertex gMeshVertices[] = {
static const GLsizei gMeshStride = sizeof(TextureVertex);
static const GLsizei gMeshCount = 4;
+/**
+ * Structure mapping Skia xfermodes to OpenGL blending factors.
+ */
+struct Blender {
+ SkXfermode::Mode mode;
+ GLenum src;
+ GLenum dst;
+}; // struct Blender
+
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
static const Blender gBlends[] = {
@@ -80,9 +89,15 @@ static const Blender gBlends[] = {
};
static const GLint gTileModes[] = {
- GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode
- GL_REPEAT, // == SkShader::kRepeat_Mode
- GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode
+ GL_CLAMP_TO_EDGE, // SkShader::kClamp_TileMode
+ GL_REPEAT, // SkShader::kRepeat_Mode
+ GL_MIRRORED_REPEAT // SkShader::kMirror_TileMode
+};
+
+static const GLenum gTextureUnits[] = {
+ GL_TEXTURE0, // Bitmap or text
+ GL_TEXTURE1, // Gradient
+ GL_TEXTURE2 // Bitmap shader
};
///////////////////////////////////////////////////////////////////////////////
@@ -119,11 +134,7 @@ OpenGLRenderer::OpenGLRenderer():
LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
}
- mDrawColorProgram = new DrawColorProgram;
- mDrawTextureProgram = new DrawTextureProgram;
- mDrawTextProgram = new DrawTextProgram;
- mDrawLinearGradientProgram = new DrawLinearGradientProgram;
- mCurrentProgram = mDrawTextureProgram;
+ mCurrentProgram = NULL;
mShader = kShaderNone;
mShaderTileX = GL_CLAMP_TO_EDGE;
@@ -131,20 +142,13 @@ OpenGLRenderer::OpenGLRenderer():
mShaderMatrix = NULL;
mShaderBitmap = NULL;
- mLastTexture = 0;
-
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
- ProgramDescription d;
- mProgramCache.get(d);
- d.hasTexture = true;
- mProgramCache.get(d);
- d.hasAlpha8Texture = true;
- d.hasGradient = true;
- d.hasBitmap = true;
- d.shadersMode = SkXfermode::kDstOut_Mode;
- d.colorOp = ProgramDescription::kColorMatrix;
- mProgramCache.get(d);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxTextureUnits);
+ if (mMaxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
+ LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
+ }
+ mLastTexture[0] = mLastTexture[1] = mLastTexture[2] = 0;
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -468,6 +472,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
const float u2 = srcRight / width;
const float v2 = srcBottom / height;
+ // TODO: Do this in the shader
resetDrawTextureTexCoords(u1, v1, u2, v2);
drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
@@ -532,6 +537,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
return;
}
+ glActiveTexture(GL_TEXTURE0);
+
float length;
switch (paint->getTextAlign()) {
case SkPaint::kCenter_Align:
@@ -558,22 +565,29 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
mModelView.loadIdentity();
- useProgram(mDrawTextProgram);
- mDrawTextProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ ProgramDescription description;
+ description.hasTexture = true;
+ description.hasAlpha8Texture = true;
+
+ useProgram(mProgramCache.get(description));
+ mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
chooseBlending(true, mode);
- bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
+
+ int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
+ glEnableVertexAttribArray(texCoordsSlot);
// Always premultiplied
- glUniform4f(mDrawTextProgram->color, r, g, b, a);
+ glUniform4f(mCurrentProgram->color, r, g, b, a);
// TODO: Implement scale properly
const Rect& clip = mSnapshot->getLocalClip();
-
mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glDisableVertexAttribArray(texCoordsSlot);
}
///////////////////////////////////////////////////////////////////////////////
@@ -599,8 +613,7 @@ void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tile
}
void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors,
- float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix,
- bool hasAlpha) {
+ float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) {
// TODO: We should use a struct to describe each shader
mShader = OpenGLRenderer::kShaderLinearGradient;
mShaderKey = shader;
@@ -650,30 +663,31 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
- if (!useProgram(mDrawColorProgram)) {
+ ProgramDescription description;
+ Program* program = mProgramCache.get(description);
+ if (!useProgram(program)) {
const GLvoid* vertices = &mMeshVertices[0].position[0];
const GLvoid* texCoords = &mMeshVertices[0].texture[0];
- glVertexAttribPointer(mDrawColorProgram->position, 2, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, vertices);
- glVertexAttribPointer(mDrawColorProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, texCoords);
}
if (!ignoreTransform) {
- mDrawColorProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
} else {
mat4 identity;
- mDrawColorProgram->set(mOrthoMatrix, mModelView, identity);
+ mCurrentProgram->set(mOrthoMatrix, mModelView, identity);
}
- glUniform4f(mDrawColorProgram->color, r, g, b, a);
+ glUniform4f(mCurrentProgram->color, r, g, b, a);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
}
void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom,
float alpha, SkXfermode::Mode mode) {
+ glActiveTexture(GL_TEXTURE1);
Texture* texture = mGradientCache.get(mShaderKey);
if (!texture) {
SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
@@ -690,14 +704,18 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right
mShaderPositions, mShaderCount, tileMode);
}
+ ProgramDescription description;
+ description.hasGradient = true;
+
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
- useProgram(mDrawLinearGradientProgram);
- mDrawLinearGradientProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ useProgram(mProgramCache.get(description));
+ mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
chooseBlending(mShaderBlend || alpha < 1.0f, mode);
- bindTexture(texture->id, mShaderTileX, mShaderTileY);
+ bindTexture(texture->id, mShaderTileX, mShaderTileY, 1);
+ glUniform1i(mCurrentProgram->getUniform("gradientSampler"), 1);
Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]);
if (mShaderMatrix) {
@@ -713,15 +731,15 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right
screenSpace.multiply(mModelView);
// Always premultiplied
- glUniform4f(mDrawLinearGradientProgram->color, alpha, alpha, alpha, alpha);
- glUniform2f(mDrawLinearGradientProgram->start, start.left, start.top);
- glUniform2f(mDrawLinearGradientProgram->gradient, gradientX, gradientY);
- glUniform1f(mDrawLinearGradientProgram->gradientLength,
+ glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
+ glUniform2f(mCurrentProgram->getUniform("gradientStart"), start.left, start.top);
+ glUniform2f(mCurrentProgram->getUniform("gradient"), gradientX, gradientY);
+ glUniform1f(mCurrentProgram->getUniform("gradientLength"),
1.0f / (gradientX * gradientX + gradientY * gradientY));
- glUniformMatrix4fv(mDrawLinearGradientProgram->screenSpace, 1, GL_FALSE,
+ glUniformMatrix4fv(mCurrentProgram->getUniform("screenSpace"), 1, GL_FALSE,
&screenSpace.data[0]);
- glVertexAttribPointer(mDrawLinearGradientProgram->position, 2, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mMeshVertices[0].position[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -729,42 +747,55 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right
void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
float alpha, SkXfermode::Mode mode) {
+ glActiveTexture(GL_TEXTURE2);
const Texture* texture = mTextureCache.get(mShaderBitmap);
const float width = texture->width;
const float height = texture->height;
- // This could be done in the vertex shader but we have only 4 vertices
- float u1 = 0.0f;
- float v1 = 0.0f;
- float u2 = right - left;
- float v2 = bottom - top;
+ mModelView.loadTranslate(left, top, 0.0f);
+ mModelView.scale(right - left, bottom - top, 1.0f);
- // TODO: If the texture is not pow, use a shader to support repeat/mirror
+ mat4 textureTransform;
if (mShaderMatrix) {
SkMatrix inverse;
mShaderMatrix->invert(&inverse);
- mat4 m(inverse);
- Rect r(u1, v1, u2, v2);
- m.mapRect(r);
+ textureTransform.load(inverse);
+ textureTransform.multiply(mModelView);
+ } else {
+ textureTransform.load(mModelView);
+ }
- u1 = r.left;
- u2 = r.right;
- v1 = r.top;
- v2 = r.bottom;
+ ProgramDescription description;
+ description.hasBitmap = true;
+ // The driver does not support non-power of two mirrored/repeated
+ // textures, so do it ourselves
+ if (!mExtensions.hasNPot()) {
+ description.isBitmapNpot = true;
+ description.bitmapWrapS = mShaderTileX;
+ description.bitmapWrapT = mShaderTileY;
}
- u1 /= width;
- u2 /= width;
- v1 /= height;
- v2 /= height;
+ useProgram(mProgramCache.get(description));
+ mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
- resetDrawTextureTexCoords(u1, v1, u2, v2);
+ chooseBlending(texture->blend || alpha < 1.0f, mode);
- drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend,
- &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
+ // Texture
+ bindTexture(texture->id, mShaderTileX, mShaderTileY, 2);
+ glUniform1i(mCurrentProgram->getUniform("bitmapSampler"), 2);
+ glUniformMatrix4fv(mCurrentProgram->getUniform("textureTransform"), 1,
+ GL_FALSE, &textureTransform.data[0]);
+ glUniform2f(mCurrentProgram->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ // Always premultiplied
+ glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
+
+ // Mesh
+ glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ gMeshStride, &mMeshVertices[0].position[0]);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
}
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
@@ -786,28 +817,37 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
+ ProgramDescription description;
+ description.hasTexture = true;
+
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
- useProgram(mDrawTextureProgram);
- mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ useProgram(mProgramCache.get(description));
+ mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
chooseBlending(blend || alpha < 1.0f, mode);
- bindTexture(texture, mShaderTileX, mShaderTileY);
+
+ // Texture
+ bindTexture(texture, mShaderTileX, mShaderTileY, 0);
+ glUniform1i(mCurrentProgram->getUniform("sampler"), 0);
// Always premultiplied
- glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
+ glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
- glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE,
+ // Mesh
+ int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
+ glEnableVertexAttribArray(texCoordsSlot);
+ glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, vertices);
- glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, texCoords);
+ glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
if (!indices) {
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
} else {
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
}
+ glDisableVertexAttribArray(texCoordsSlot);
}
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
@@ -836,9 +876,9 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr
mBlend = blend;
}
-bool OpenGLRenderer::useProgram(const sp<Program>& program) {
+bool OpenGLRenderer::useProgram(Program* program) {
if (!program->isInUse()) {
- mCurrentProgram->remove();
+ if (mCurrentProgram != NULL) mCurrentProgram->remove();
program->use();
mCurrentProgram = program;
return false;
@@ -875,12 +915,12 @@ void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermod
}
}
-void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT) {
- if (texture != mLastTexture) {
+void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
+ glActiveTexture(gTextureUnits[textureUnit]);
+ if (texture != mLastTexture[textureUnit]) {
glBindTexture(GL_TEXTURE_2D, texture);
- mLastTexture = texture;
+ mLastTexture[textureUnit] = texture;
}
- // TODO: Don't set the texture parameters every time
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 975be05..5e5c021 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -47,22 +47,11 @@ namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
-// Support
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
-struct Blender {
- SkXfermode::Mode mode;
- GLenum src;
- GLenum dst;
-}; // struct Blender
-
-///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
+#define REQUIRED_TEXTURE_UNITS_COUNT 3
+
/**
* OpenGL renderer used to draw accelerated 2D graphics. The API is a
* simplified version of Skia's Canvas API.
@@ -294,7 +283,7 @@ private:
/**
* Binds the specified texture with the specified wrap modes.
*/
- inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT);
+ inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit = 0);
/**
* Enable or disable blending as necessary. This function sets the appropriate
@@ -312,7 +301,7 @@ private:
*
* @return true If the specified program was already in use, false otherwise.
*/
- inline bool useProgram(const sp<Program>& program);
+ inline bool useProgram(Program* program);
// Dimensions of the drawing surface
int mWidth, mHeight;
@@ -331,17 +320,14 @@ private:
sp<Snapshot> mSnapshot;
// Shaders
- sp<Program> mCurrentProgram;
- sp<DrawColorProgram> mDrawColorProgram;
- sp<DrawTextureProgram> mDrawTextureProgram;
- sp<DrawTextProgram> mDrawTextProgram;
- sp<DrawLinearGradientProgram> mDrawLinearGradientProgram;
+ Program* mCurrentProgram;
// Used to draw textured quads
TextureVertex mMeshVertices[4];
// Current texture state
- GLuint mLastTexture;
+ GLuint mLastTexture[REQUIRED_TEXTURE_UNITS_COUNT];
+ GLint mMaxTextureUnits;
// Last known blend state
bool mBlend;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 86fc154..dbae38e 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -27,16 +27,6 @@ namespace uirenderer {
#define SHADER_SOURCE(name, source) const char* name = #source
-#include "shaders/drawColor.frag"
-
-#include "shaders/drawTexture.vert"
-#include "shaders/drawTexture.frag"
-
-#include "shaders/drawText.frag"
-
-#include "shaders/drawLinearGradient.vert"
-#include "shaders/drawLinearGradient.frag"
-
///////////////////////////////////////////////////////////////////////////////
// Base program
///////////////////////////////////////////////////////////////////////////////
@@ -65,6 +55,10 @@ Program::Program(const char* vertex, const char* fragment) {
}
mUse = false;
+
+ position = addAttrib("position");
+ color = addUniform("color");
+ transform = addUniform("transform");
}
Program::~Program() {
@@ -73,15 +67,6 @@ Program::~Program() {
glDeleteProgram(id);
}
-void Program::use() {
- glUseProgram(id);
- mUse = true;
-}
-
-void Program::remove() {
- mUse = false;
-}
-
int Program::addAttrib(const char* name) {
int slot = glGetAttribLocation(id, name);
attributes.add(name, slot);
@@ -89,7 +74,11 @@ int Program::addAttrib(const char* name) {
}
int Program::getAttrib(const char* name) {
- return attributes.valueFor(name);
+ ssize_t index = attributes.indexOfKey(name);
+ if (index >= 0) {
+ return attributes.valueAt(index);
+ }
+ return addAttrib(name);
}
int Program::addUniform(const char* name) {
@@ -99,7 +88,11 @@ int Program::addUniform(const char* name) {
}
int Program::getUniform(const char* name) {
- return uniforms.valueFor(name);
+ ssize_t index = uniforms.indexOfKey(name);
+ if (index >= 0) {
+ return uniforms.valueAt(index);
+ }
+ return addUniform(name);
}
GLuint Program::buildShader(const char* source, GLenum type) {
@@ -121,28 +114,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
return shader;
}
-///////////////////////////////////////////////////////////////////////////////
-// Draw color
-///////////////////////////////////////////////////////////////////////////////
-
-DrawColorProgram::DrawColorProgram():
- Program(gDrawTextureVertexShader, gDrawColorFragmentShader) {
- getAttribsAndUniforms();
-}
-
-DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment):
- Program(vertex, fragment) {
- getAttribsAndUniforms();
-}
-
-void DrawColorProgram::getAttribsAndUniforms() {
- position = addAttrib("position");
- texCoords = addAttrib("texCoords");
- color = addUniform("color");
- transform = addUniform("transform");
-}
-
-void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
+void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
const mat4& transformMatrix) {
mat4 t(projectionMatrix);
t.multiply(transformMatrix);
@@ -151,70 +123,17 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa
glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
}
-void DrawColorProgram::use() {
- Program::use();
- glEnableVertexAttribArray(position);
- glEnableVertexAttribArray(texCoords);
-}
-
-void DrawColorProgram::remove() {
- Program::remove();
- glDisableVertexAttribArray(position);
- glDisableVertexAttribArray(texCoords);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Draw texture
-///////////////////////////////////////////////////////////////////////////////
-
-DrawTextureProgram::DrawTextureProgram():
- DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) {
- sampler = addUniform("sampler");
-}
-
-DrawTextureProgram::DrawTextureProgram(const char* vertex, const char* fragment):
- DrawColorProgram(vertex, fragment) {
- sampler = addUniform("sampler");
-}
-
-void DrawTextureProgram::use() {
- DrawColorProgram::use();
- glUniform1i(sampler, 0);
-}
-
-void DrawTextureProgram::remove() {
- DrawColorProgram::remove();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Draw text
-///////////////////////////////////////////////////////////////////////////////
-
-DrawTextProgram::DrawTextProgram():
- DrawTextureProgram(gDrawTextureVertexShader, gDrawTextFragmentShader) {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Draw linear gradient
-///////////////////////////////////////////////////////////////////////////////
+void Program::use() {
+ glUseProgram(id);
+ mUse = true;
-DrawLinearGradientProgram::DrawLinearGradientProgram():
- DrawColorProgram(gDrawLinearGradientVertexShader, gDrawLinearGradientFragmentShader) {
- gradient = addUniform("gradient");
- gradientLength = addUniform("gradientLength");
- sampler = addUniform("sampler");
- start = addUniform("start");
- screenSpace = addUniform("screenSpace");
+ glEnableVertexAttribArray(position);
}
-void DrawLinearGradientProgram::use() {
- DrawColorProgram::use();
- glActiveTexture(GL_TEXTURE0);
- glUniform1i(sampler, 0);
-}
+void Program::remove() {
+ mUse = false;
-void DrawLinearGradientProgram::remove() {
- DrawColorProgram::remove();
+ glDisableVertexAttribArray(position);
}
}; // namespace uirenderer
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 2cdd905..6531c74 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -21,7 +21,6 @@
#include <GLES2/gl2ext.h>
#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
#include "Matrix.h"
@@ -32,7 +31,7 @@ namespace uirenderer {
* A program holds a vertex and a fragment shader. It offers several utility
* methods to query attributes and uniforms.
*/
-class Program: public LightRefBase<Program> {
+class Program {
public:
/**
* Creates a new program with the specified vertex and fragment
@@ -70,6 +69,28 @@ public:
return mUse;
}
+ /**
+ * Binds the program with the specified projection, modelView and
+ * transform matrices.
+ */
+ void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
+ const mat4& transformMatrix);
+
+ /**
+ * Name of the position attribute.
+ */
+ int position;
+
+ /**
+ * Name of the color uniform.
+ */
+ int color;
+
+ /**
+ * Name of the transform uniform.
+ */
+ int transform;
+
protected:
/**
* Adds an attribute with the specified name.
@@ -107,146 +128,6 @@ private:
bool mUse;
}; // class Program
-/**
- * Program used to draw vertices with a simple color. The shaders must
- * specify the following attributes:
- * vec4 position, position of the vertex
- * vec4 color, RGBA color of the vertex
- *
- * And the following uniforms:
- * mat4 projection, the projection matrix
- * mat4 modelView, the modelView matrix
- * mat4 transform, an extra transformation matrix
- */
-class DrawColorProgram: public Program {
-public:
- DrawColorProgram();
- DrawColorProgram(const char* vertex, const char* fragment);
-
- /**
- * Binds the program with the specified projection, modelView and
- * transform matrices.
- */
- void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
- const mat4& transformMatrix);
-
- /**
- * Binds this program to the GL context.
- */
- virtual void use();
-
- /**
- * Marks this program as unused. This will not unbind
- * the program from the GL context.
- */
- virtual void remove();
-
- /**
- * Name of the position attribute.
- */
- int position;
-
- /**
- * Name of the texture coordinates attribute.
- */
- int texCoords;
-
- /**
- * Name of the color uniform.
- */
- int color;
-
- /**
- * Name of the transform uniform.
- */
- int transform;
-
-protected:
- void getAttribsAndUniforms();
-};
-
-/**
- * Program used to draw textured vertices. In addition to everything that the
- * DrawColorProgram supports, the following two attributes must be specified:
- * sampler2D sampler, the texture sampler
- * vec2 texCoords, the texture coordinates of the vertex
- */
-class DrawTextureProgram: public DrawColorProgram {
-public:
- DrawTextureProgram();
- DrawTextureProgram(const char* vertex, const char* fragment);
-
- /**
- * Binds this program to the GL context.
- */
- virtual void use();
-
- /**
- * Marks this program as unused. This will not unbind
- * the program from the GL context.
- */
- virtual void remove();
-
- /**
- * Name of the texture sampler uniform.
- */
- int sampler;
-};
-
-class DrawTextProgram: public DrawTextureProgram {
-public:
- DrawTextProgram();
-};
-
-/**
- * Program used to draw linear gradients. In addition to everything that the
- * DrawColorProgram supports, the following two attributes must be specified:
- * vec2 gradient, the vector describing the linear gradient
- * float gradientLength, the invert of the magnitude of the gradient vector
- * sampler2D sampler, the texture sampler
- */
-class DrawLinearGradientProgram: public DrawColorProgram {
-public:
- DrawLinearGradientProgram();
-
- /**
- * Binds this program to the GL context.
- */
- virtual void use();
-
- /**
- * Marks this program as unused. This will not unbind
- * the program from the GL context.
- */
- virtual void remove();
-
- /**
- * Name of the matrix used to compute the screen space coordinates
- * of the vertices.
- */
- int screenSpace;
-
- /**
- * Name of the linear gradient start point.
- */
- int start;
-
- /**
- * Name of the linear gradient vector.
- */
- int gradient;
-
- /**
- * Name of the inverse of linear gradient vector's magnitude.
- */
- int gradientLength;
-
- /**
- * Name of the texture sampler uniform.
- */
- int sampler;
-};
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 5a89eb6..c9e2d2e 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -40,6 +40,9 @@ const char* gVS_Header_Uniforms_HasGradient =
"uniform vec2 gradient;\n"
"uniform vec2 gradientStart;\n"
"uniform mat4 screenSpace;\n";
+const char* gVS_Header_Uniforms_HasBitmap =
+ "uniform mat4 textureTransform;\n"
+ "uniform vec2 textureDimension;\n";
const char* gVS_Header_Varyings_HasTexture =
"varying vec2 outTexCoords;\n";
const char* gVS_Header_Varyings_HasBitmap =
@@ -53,6 +56,9 @@ const char* gVS_Main_OutTexCoords =
const char* gVS_Main_OutGradientIndex =
" vec4 location = screenSpace * position;\n"
" index = dot(location.xy - gradientStart, gradient) * gradientLength;\n";
+const char* gVS_Main_OutBitmapTexCoords =
+ " vec4 bitmapCoords = textureTransform * position;\n"
+ " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n";
const char* gVS_Main_Position =
" gl_Position = transform * position;\n";
const char* gVS_Footer =
@@ -97,12 +103,18 @@ const char* gFS_Main_FetchGradient =
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n";
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
+const char* gFS_Main_FetchBitmapNpot =
+ " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
const char* gFS_Main_BlendShadersBG =
" fragColor = blendShaders(bitmapColor, gradientColor)";
const char* gFS_Main_BlendShadersGB =
" fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShaders_Modulate =
" * fragColor.a;\n";
+const char* gFS_Main_GradientShader_Modulate =
+ " fragColor = gradientColor * fragColor.a;\n";
+const char* gFS_Main_BitmapShader_Modulate =
+ " fragColor = bitmapColor * fragColor.a;\n";
const char* gFS_Main_FragColor =
" gl_FragColor = fragColor;\n";
const char* gFS_Main_ApplyColorOp[4] = {
@@ -204,7 +216,7 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
// Add attributes
String8 shader(gVS_Header_Attributes);
- if (description.hasTexture || description.hasBitmap) {
+ if (description.hasTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
// Uniforms
@@ -212,6 +224,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasGradient) {
shader.append(gVS_Header_Uniforms_HasGradient);
}
+ if (description.hasBitmap) {
+ shader.append(gVS_Header_Uniforms_HasBitmap);
+ }
// Varyings
if (description.hasTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
@@ -231,6 +246,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasGradient) {
shader.append(gVS_Main_OutGradientIndex);
}
+ if (description.hasBitmap) {
+ shader.append(gVS_Main_OutBitmapTexCoords);
+ }
// Output transformed position
shader.append(gVS_Main_Position);
}
@@ -278,6 +296,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.colorOp == ProgramDescription::kColorBlend) {
generatePorterDuffBlend(shader, "blendColors", description.colorMode);
}
+ if (description.isBitmapNpot) {
+ generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
+ }
// Begin the shader
shader.append(gFS_Main); {
@@ -295,7 +316,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Main_FetchGradient);
}
if (description.hasBitmap) {
- shader.append(gFS_Main_FetchBitmap);
+ if (!description.isBitmapNpot) {
+ shader.append(gFS_Main_FetchBitmap);
+ } else {
+ shader.append(gFS_Main_FetchBitmapNpot);
+ }
}
// Case when we have two shaders set
if (description.hasGradient && description.hasBitmap) {
@@ -305,6 +330,12 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Main_BlendShadersGB);
}
shader.append(gFS_Main_BlendShaders_Modulate);
+ } else {
+ if (description.hasGradient) {
+ shader.append(gFS_Main_GradientShader_Modulate);
+ } else if (description.hasBitmap) {
+ shader.append(gFS_Main_BitmapShader_Modulate);
+ }
}
// Apply the color op if needed
shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
@@ -328,5 +359,37 @@ void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name,
shader.append("}\n");
}
+void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
+ shader.append("\nvec2 wrap(vec2 texCoords) {\n");
+ if (wrapS == GL_MIRRORED_REPEAT) {
+ shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n");
+ shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
+ }
+ if (wrapT == GL_MIRRORED_REPEAT) {
+ shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n");
+ shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
+ }
+ shader.append(" return vec2(");
+ switch (wrapS) {
+ case GL_REPEAT:
+ shader.append("mod(texCoords.x, 1.0)");
+ break;
+ case GL_MIRRORED_REPEAT:
+ shader.append("xMod2");
+ break;
+ }
+ shader.append(", ");
+ switch (wrapT) {
+ case GL_REPEAT:
+ shader.append("mod(texCoords.y, 1.0)");
+ break;
+ case GL_MIRRORED_REPEAT:
+ shader.append("yMod2");
+ break;
+ }
+ shader.append(");\n");
+ shader.append("}\n");
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 7f2f5fa..5a6ec33 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -20,6 +20,8 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
+#include <GLES2/gl2.h>
+
#include <SkXfermode.h>
#include "Program.h"
@@ -32,7 +34,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Debug
-#define DEBUG_PROGRAM_CACHE 0
+#define DEBUG_PROGRAM_CACHE 1
// Debug
#if DEBUG_PROGRAM_CACHE
@@ -49,12 +51,19 @@ namespace uirenderer {
#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_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
// Support only the 12 Porter-Duff modes for now
#define PROGRAM_MAX_XFERMODE 0xC
#define PROGRAM_XFERMODE_SHADER_SHIFT 24
#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
+#define PROGRAM_BITMAP_WRAPS_SHIFT 9
+#define PROGRAM_BITMAP_WRAPT_SHIFT 11
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -80,7 +89,9 @@ struct ProgramDescription {
ProgramDescription():
hasTexture(false), hasAlpha8Texture(false),
- hasBitmap(false), hasGradient(false), shadersMode(SkXfermode::kClear_Mode),
+ hasBitmap(false), isBitmapNpot(false), hasGradient(false),
+ shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false),
+ bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE),
colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode) {
}
@@ -90,19 +101,41 @@ struct ProgramDescription {
// Shaders
bool hasBitmap;
+ bool isBitmapNpot;
bool hasGradient;
SkXfermode::Mode shadersMode;
bool isBitmapFirst;
+ GLenum bitmapWrapS;
+ GLenum bitmapWrapT;
// Color operations
int colorOp;
SkXfermode::Mode colorMode;
+ 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;
+ }
+
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 (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;
if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
if (hasBitmap && hasGradient) {
@@ -144,6 +177,7 @@ private:
String8 generateVertexShader(const ProgramDescription& description);
String8 generateFragmentShader(const ProgramDescription& description);
void generatePorterDuffBlend(String8& shader, const char* name, SkXfermode::Mode mode);
+ void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
KeyedVector<programid, Program*> mCache;
diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag
deleted file mode 100644
index 1d6cb8b..0000000
--- a/libs/hwui/shaders/drawColor.frag
+++ /dev/null
@@ -1,11 +0,0 @@
-SHADER_SOURCE(gDrawColorFragmentShader,
-
-precision mediump float;
-
-uniform vec4 color;
-
-void main(void) {
- gl_FragColor = color;
-}
-
-);
diff --git a/libs/hwui/shaders/drawLinearGradient.frag b/libs/hwui/shaders/drawLinearGradient.frag
deleted file mode 100644
index 469c662..0000000
--- a/libs/hwui/shaders/drawLinearGradient.frag
+++ /dev/null
@@ -1,14 +0,0 @@
-SHADER_SOURCE(gDrawLinearGradientFragmentShader,
-
-precision mediump float;
-
-varying float index;
-
-uniform vec4 color;
-uniform sampler2D sampler;
-
-void main(void) {
- gl_FragColor = texture2D(sampler, vec2(index, 0.5)) * color;
-}
-
-);
diff --git a/libs/hwui/shaders/drawLinearGradient.vert b/libs/hwui/shaders/drawLinearGradient.vert
deleted file mode 100644
index d2f857d..0000000
--- a/libs/hwui/shaders/drawLinearGradient.vert
+++ /dev/null
@@ -1,20 +0,0 @@
-SHADER_SOURCE(gDrawLinearGradientVertexShader,
-
-attribute vec4 position;
-
-uniform mat4 transform;
-uniform float gradientLength;
-uniform vec2 gradient;
-uniform vec2 start;
-uniform mat4 screenSpace;
-
-varying float index;
-
-void main(void) {
- vec4 location = screenSpace * position;
- index = dot(location.xy - start, gradient) * gradientLength;
-
- gl_Position = transform * position;
-}
-
-);
diff --git a/libs/hwui/shaders/drawText.frag b/libs/hwui/shaders/drawText.frag
deleted file mode 100644
index 49532c7..0000000
--- a/libs/hwui/shaders/drawText.frag
+++ /dev/null
@@ -1,14 +0,0 @@
-SHADER_SOURCE(gDrawTextFragmentShader,
-
-precision mediump float;
-
-varying vec2 outTexCoords;
-
-uniform vec4 color;
-uniform sampler2D sampler;
-
-void main(void) {
- gl_FragColor = color * texture2D(sampler, outTexCoords).a;
-}
-
-);
diff --git a/libs/hwui/shaders/drawTexture.frag b/libs/hwui/shaders/drawTexture.frag
deleted file mode 100644
index 8390d8e..0000000
--- a/libs/hwui/shaders/drawTexture.frag
+++ /dev/null
@@ -1,14 +0,0 @@
-SHADER_SOURCE(gDrawTextureFragmentShader,
-
-precision mediump float;
-
-varying vec2 outTexCoords;
-
-uniform vec4 color;
-uniform sampler2D sampler;
-
-void main(void) {
- gl_FragColor = texture2D(sampler, outTexCoords) * color;
-}
-
-);
diff --git a/libs/hwui/shaders/drawTexture.vert b/libs/hwui/shaders/drawTexture.vert
deleted file mode 100644
index 240aebf..0000000
--- a/libs/hwui/shaders/drawTexture.vert
+++ /dev/null
@@ -1,15 +0,0 @@
-SHADER_SOURCE(gDrawTextureVertexShader,
-
-attribute vec4 position;
-attribute vec2 texCoords;
-
-uniform mat4 transform;
-
-varying vec2 outTexCoords;
-
-void main(void) {
- outTexCoords = texCoords;
- gl_Position = transform * position;
-}
-
-);