summaryrefslogtreecommitdiffstats
path: root/libs/hwui/OpenGLRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
-rw-r--r--libs/hwui/OpenGLRenderer.cpp194
1 files changed, 117 insertions, 77 deletions
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);
}