summaryrefslogtreecommitdiffstats
path: root/libs/hwui/GlopBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/GlopBuilder.cpp')
-rw-r--r--libs/hwui/GlopBuilder.cpp145
1 files changed, 114 insertions, 31 deletions
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index dafe087..e22af40 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -18,10 +18,12 @@
#include "Caches.h"
#include "Glop.h"
#include "Matrix.h"
-#include "Texture.h"
#include "renderstate/MeshState.h"
#include "renderstate/RenderState.h"
+#include "SkiaShader.h"
+#include "Texture.h"
#include "utils/PaintUtils.h"
+#include "VertexBuffer.h"
#include <GLES2/gl2.h>
#include <SkPaint.h>
@@ -29,42 +31,82 @@
namespace android {
namespace uirenderer {
+#define TRIGGER_STAGE(stageFlag) \
+ LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
+ mStageFlags = static_cast<StageFlags>(mStageFlags | stageFlag)
+
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
: mRenderState(renderState)
, mCaches(caches)
, mOutGlop(outGlop){
+ mStageFlags = kInitialStage;
+}
+
+GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
+ TRIGGER_STAGE(kMeshStage);
+
+ const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
+
+ bool alphaVertex = flags & VertexBuffer::kAlpha;
+ bool indices = flags & VertexBuffer::kIndices;
+ mOutGlop->mesh.vertexFlags = alphaVertex ? kAlpha_Attrib : kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = vertexBuffer.getIndices();
+ mOutGlop->mesh.vertexCount = indices
+ ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+ mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
+
+ mDescription.hasVertexAlpha = alphaVertex;
+ mDescription.useShadowAlphaInterp = shadowInterp;
+ return *this;
}
GlopBuilder& GlopBuilder::setMeshUnitQuad() {
- mOutGlop->mesh.vertexFlags = static_cast<VertexAttribFlags>(0);
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
mOutGlop->mesh.vertexCount = 4;
mOutGlop->mesh.stride = kTextureVertexStride;
return *this;
}
-GlopBuilder& GlopBuilder::setTransformAndRect(ModelViewMode mode,
- const Matrix4& ortho, const Matrix4& transform,
- float left, float top, float right, float bottom, bool offset) {
- mOutGlop->transform.ortho.load(ortho);
-
- mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
- if (mode == kModelViewMode_TranslateAndScale) {
- mOutGlop->transform.modelView.scale(right - left, bottom - top, 1.0f);
- }
+GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
+ const Matrix4& transform, bool fudgingOffset) {
+ TRIGGER_STAGE(kTransformStage);
+ mOutGlop->transform.ortho.load(ortho);
mOutGlop->transform.canvas.load(transform);
+ mOutGlop->transform.fudgingOffset = fudgingOffset;
+ return *this;
+}
- mOutGlop->transform.offset = offset;
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+ mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
- mOutGlop->bounds.set(left, top, right, bottom);
- mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+ TRIGGER_STAGE(kModelViewStage);
+ mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+ mOutGlop->bounds = source;
+ mOutGlop->bounds.translate(offsetX, offsetY);
return *this;
}
GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+
// TODO: support null paint
const SkShader* shader = paint->getShader();
const SkColorFilter* colorFilter = paint->getColorFilter();
@@ -73,25 +115,25 @@ GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) {
if (mode != SkXfermode::kClear_Mode) {
int color = paint->getColor();
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
- if (shader) {
- // shader discards color channels
- color |= 0x00FFFFFF;
+ if (!shader) {
+ float colorScale = alpha / 255.0f;
+ mOutGlop->fill.color = {
+ alpha,
+ colorScale * SkColorGetR(color),
+ colorScale * SkColorGetG(color),
+ colorScale * SkColorGetB(color)
+ };
+ } else {
+ mOutGlop->fill.color = { alpha, 1, 1, 1 };
}
- mOutGlop->fill.color = {
- alpha,
- alpha * SkColorGetR(color),
- alpha * SkColorGetG(color),
- alpha * SkColorGetB(color)
- };
} else {
mOutGlop->fill.color = { 1, 0, 0, 0 };
}
const bool SWAP_SRC_DST = false;
- const bool HAS_FRAMEBUFFER_FETCH = false; //mExtensions.hasFramebufferFetch();
- mOutGlop->blend = {GL_ZERO, GL_ZERO};
+ mOutGlop->blend = { GL_ZERO, GL_ZERO };
if (mOutGlop->fill.color.a < 1.0f
- || (shader && !shader->isOpaque())
+ || PaintUtils::isBlendedShader(shader)
|| PaintUtils::isBlendedColorFilter(colorFilter)
|| mode != SkXfermode::kSrcOver_Mode) {
if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
@@ -103,7 +145,7 @@ GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) {
// the blending, don't enable GL blending off here
// If the blend mode cannot be implemented using shaders, fall
// back to the default SrcOver blend mode instead
- if (CC_UNLIKELY(HAS_FRAMEBUFFER_FETCH)) {
+ if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
mDescription.framebufferMode = mode;
mDescription.swapSrcDst = SWAP_SRC_DST;
// blending in shader, don't enable
@@ -115,17 +157,58 @@ GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) {
}
}
- return *this;
-}
+ if (shader) {
+ SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
+ // TODO: store shader data
+ LOG_ALWAYS_FATAL("shaders not yet supported");
+ }
+
+ if (colorFilter) {
+ SkColor color;
+ SkXfermode::Mode mode;
+ SkScalar srcColorMatrix[20];
+ if (colorFilter->asColorMode(&color, &mode)) {
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+ mDescription.colorMode = mode;
+
+ const float alpha = SkColorGetA(color) / 255.0f;
+ float colorScale = alpha / 255.0f;
+ mOutGlop->fill.filter.color = {
+ alpha,
+ colorScale * SkColorGetR(color),
+ colorScale * SkColorGetG(color),
+ colorScale * SkColorGetB(color),
+ };
+ } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+
+ float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
+ memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+ memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+ memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+ memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+ // Skia uses the range [0..255] for the addition vector, but we need
+ // the [0..1] range to apply the vector in GLSL
+ float* colorVector = mOutGlop->fill.filter.matrix.vector;
+ colorVector[0] = srcColorMatrix[4] / 255.0f;
+ colorVector[1] = srcColorMatrix[9] / 255.0f;
+ colorVector[2] = srcColorMatrix[14] / 255.0f;
+ colorVector[3] = srcColorMatrix[19] / 255.0f;
+ }
+ } else {
+ mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+ }
-GlopBuilder& GlopBuilder::setTexture(Texture* texture) {
- LOG_ALWAYS_FATAL("not yet supported");
return *this;
}
void GlopBuilder::build() {
+ LOG_ALWAYS_FATAL_IF(mStageFlags != kAllStages, "glop not fully prepared!");
+
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+ mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
}
} /* namespace uirenderer */