Glop ColorFilter & VertexBuffer support, initial enable

Enables Glop rendering for supported Rects and VertexBuffers
Also removes unused Query object

Change-Id: Ibe227bc362685a153159f75077664f0947764e06
This commit is contained in:
Chris Craik
2015-02-05 10:12:38 -08:00
parent 3472568774
commit 117bdbcfa3
39 changed files with 443 additions and 415 deletions

View File

@@ -179,7 +179,7 @@ inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
shadowVertexBuffer.setMode(VertexBuffer::kIndices);
shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
// In order to computer the outer vertices in one loop, we need pre-compute
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value

View File

@@ -48,10 +48,11 @@ Caches* Caches::sInstance = nullptr;
///////////////////////////////////////////////////////////////////////////////
Caches::Caches(RenderState& renderState)
: patchCache(renderState)
: gradientCache(mExtensions)
, patchCache(renderState)
, programCache(mExtensions)
, dither(*this)
, mRenderState(&renderState)
, mExtensions(Extensions::getInstance())
, mInitialized(false) {
INIT_LOGD("Creating OpenGL renderer caches");
init();
@@ -187,9 +188,9 @@ bool Caches::initProperties() {
INIT_LOGD(" Draw reorder enabled");
}
return (prevDebugLayersUpdates != debugLayersUpdates) ||
(prevDebugOverdraw != debugOverdraw) ||
(prevDebugStencilClip != debugStencilClip);
return (prevDebugLayersUpdates != debugLayersUpdates)
|| (prevDebugOverdraw != debugOverdraw)
|| (prevDebugStencilClip != debugStencilClip);
}
void Caches::terminate() {

View File

@@ -178,14 +178,18 @@ public:
kStencilShowRegion
};
StencilClipDebug debugStencilClip;
private:
// Declared before gradientCache and programCache which need this to initialize.
// TODO: cleanup / move elsewhere
Extensions mExtensions;
public:
TextureCache textureCache;
LayerCache layerCache;
RenderBufferCache renderBufferCache;
GradientCache gradientCache;
ProgramCache programCache;
PathCache pathCache;
PatchCache patchCache;
PathCache pathCache;
ProgramCache programCache;
TessellationCache tessellationCache;
TextDropShadowCache dropShadowCache;
FboCache fboCache;
@@ -220,6 +224,7 @@ public:
void setProgram(const ProgramDescription& description);
void setProgram(Program* program);
Extensions& extensions() { return mExtensions; }
Program& program() { return *mProgram; }
PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
TextureState& textureState() { return *mTextureState; }
@@ -248,7 +253,6 @@ private:
}
RenderState* mRenderState;
Extensions& mExtensions;
// Used to render layers
std::unique_ptr<TextureVertex[]> mRegionMesh;

View File

@@ -32,8 +32,6 @@ Dither::Dither(Caches& caches)
void Dither::bindDitherTexture() {
if (!mInitialized) {
bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
glGenTextures(1, &mDitherTexture);
mCaches.textureState().bindTexture(mDitherTexture);
@@ -43,7 +41,7 @@ void Dither::bindDitherTexture() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (useFloatTexture) {
if (mCaches.extensions().hasFloatTextures()) {
// We use a R16F texture, let's remap the alpha channel to the
// red channel to avoid changing the shader sampling code on GL ES 3.0+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);

View File

@@ -23,6 +23,7 @@ namespace android {
namespace uirenderer {
class Caches;
class Extensions;
class Program;
// Must be a power of two

View File

@@ -16,18 +16,16 @@
#define LOG_TAG "OpenGLRenderer"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include "Extensions.h"
#include "Debug.h"
#include "Properties.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2ext.h>
#include <utils/Log.h>
#include "Debug.h"
#include "Extensions.h"
#include "Properties.h"
namespace android {
using namespace uirenderer;
@@ -50,7 +48,7 @@ namespace uirenderer {
// Constructors
///////////////////////////////////////////////////////////////////////////////
Extensions::Extensions(): Singleton<Extensions>() {
Extensions::Extensions() {
// Query GL extensions
findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
mHasNPot = hasGlExtension("GL_OES_texture_npot");
@@ -93,9 +91,6 @@ Extensions::Extensions(): Singleton<Extensions>() {
}
}
Extensions::~Extensions() {
}
///////////////////////////////////////////////////////////////////////////////
// Methods
///////////////////////////////////////////////////////////////////////////////

View File

@@ -23,6 +23,8 @@
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <GLES2/gl2.h>
namespace android {
namespace uirenderer {
@@ -30,8 +32,10 @@ namespace uirenderer {
// Classes
///////////////////////////////////////////////////////////////////////////////
class ANDROID_API Extensions: public Singleton<Extensions> {
class ANDROID_API Extensions {
public:
Extensions();
inline bool hasNPot() const { return mHasNPot; }
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
@@ -55,13 +59,8 @@ public:
void dump() const;
private:
Extensions();
~Extensions();
void findExtensions(const char* extensions, SortedVector<String8>& list) const;
friend class Singleton<Extensions>;
SortedVector<String8> mGlExtensionList;
SortedVector<String8> mEglExtensionList;

View File

@@ -38,11 +38,13 @@ class Program;
*/
enum VertexAttribFlags {
// NOTE: position attribute always enabled
kNone_Attrib = 0,
kTextureCoord_Attrib = 1 << 0,
kColor_Attrib = 1 << 1,
kAlpha_Attrib = 1 << 2,
};
/**
* Structure containing all data required to issue a single OpenGL draw
*
@@ -53,40 +55,53 @@ enum VertexAttribFlags {
*/
// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
struct Glop {
struct FloatColor {
float a, r, g, b;
};
Rect bounds;
/*
* Stores mesh - vertex and index data.
*
* buffer objects and void*s are mutually exclusive
* indices are optional
*/
struct Mesh {
VertexAttribFlags vertexFlags;
GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
GLuint vertexBufferObject;
GLuint indexBufferObject;
const void* vertices;
const void* indices;
int vertexCount;
GLsizei stride;
} mesh;
struct Fill {
Program* program;
struct Color {
float a, r, g, b;
} color;
FloatColor color;
/* TODO
union shader {
//...
}; TODO
union filter {
//color
//matrix + vector
};
*/
ProgramDescription::ColorFilterMode filterMode;
union Filter {
struct Matrix {
float matrix[16];
float vector[4];
} matrix;
FloatColor color;
} filter;
} fill;
struct Transform {
Matrix4 ortho; // TODO: out of op, since this is static per FBO
Matrix4 modelView;
Matrix4 canvas;
bool offset;
bool fudgingOffset;
} transform;
struct Blend {

View File

@@ -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) {
GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
const Matrix4& transform, bool fudgingOffset) {
TRIGGER_STAGE(kTransformStage);
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);
}
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 */

View File

@@ -27,22 +27,35 @@ namespace uirenderer {
class Caches;
struct Glop;
class Matrix4;
class RenderState;
class Texture;
class Matrix4;
class VertexBuffer;
class GlopBuilder {
PREVENT_COPY_AND_ASSIGN(GlopBuilder);
public:
GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
GlopBuilder& setMeshUnitQuad();
GlopBuilder& setTransformAndRect(ModelViewMode mode,
const Matrix4& ortho, const Matrix4& transform,
float left, float top, float right, float bottom, bool offset);
GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
GlopBuilder& setPaint(const SkPaint* paint, float alphaScale);
GlopBuilder& setTexture(Texture* texture);
void build();
private:
enum StageFlags {
kInitialStage = 0,
kMeshStage = 1 << 0,
kTransformStage = 1 << 1,
kModelViewStage = 1 << 2,
kFillStage = 1 << 3,
kAllStages = kMeshStage | kTransformStage | kModelViewStage | kFillStage,
} mStageFlags;
ProgramDescription mDescription;
RenderState& mRenderState;
Caches& mCaches;

View File

@@ -62,9 +62,12 @@ int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCac
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
GradientCache::GradientCache():
mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
GradientCache::GradientCache(Extensions& extensions)
: mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
, mSize(0)
, mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE))
, mUseFloatTexture(extensions.hasFloatTextures())
, mHasNpot(extensions.hasNPot()){
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting gradient cache size to %sMB", property);
@@ -76,16 +79,6 @@ GradientCache::GradientCache():
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
mCache.setOnEntryRemovedListener(this);
const Extensions& extensions = Extensions::getInstance();
mUseFloatTexture = extensions.hasFloatTextures();
mHasNpot = extensions.hasNPot();
}
GradientCache::GradientCache(uint32_t maxByteSize):
mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
mCache.setOnEntryRemovedListener(this);
}
GradientCache::~GradientCache() {

View File

@@ -104,8 +104,7 @@ inline hash_t hash_type(const GradientCacheEntry& entry) {
*/
class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
public:
GradientCache();
GradientCache(uint32_t maxByteSize);
GradientCache(Extensions& extensions);
~GradientCache();
/**

View File

@@ -337,7 +337,7 @@ void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
if (fbo) {
// If possible, discard any enqueud operations on deferred
// rendering architectures
if (Extensions::getInstance().hasDiscardFramebuffer()) {
if (Caches::getInstance().extensions().hasDiscardFramebuffer()) {
GLuint previousFbo = renderState.getFramebuffer();
if (fbo != previousFbo) {
renderState.bindFramebuffer(fbo);

View File

@@ -89,7 +89,6 @@ static inline T min(T a, T b) {
OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
: mState(*this)
, mCaches(Caches::getInstance())
, mExtensions(Extensions::getInstance())
, mRenderState(renderState)
, mFrameStarted(false)
, mScissorOptimizationDisabled(false)
@@ -195,7 +194,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
// If we know that we are going to redraw the entire framebuffer,
// perform a discard to let the driver know we don't need to preserve
// the back buffer for this frame.
if (mExtensions.hasDiscardFramebuffer() &&
if (mCaches.extensions().hasDiscardFramebuffer() &&
left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
const bool isFbo = onGetTargetFbo() == 0;
const GLenum attachments[] = {
@@ -905,7 +904,7 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -947,7 +946,7 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
layer->getTexture(), &layerPaint, blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, kMeshCount, swap, swap || simpleTransform);
GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
@@ -1387,7 +1386,8 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
endTiling();
RenderBuffer* buffer = mCaches.renderBufferCache.get(
Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
Stencil::getSmallestStencilFormat(),
layer->getWidth(), layer->getHeight());
layer->setStencilRenderBuffer(buffer);
startTiling(layer->clipRect, layer->layer.getHeight());
@@ -1573,6 +1573,18 @@ void OpenGLRenderer::debugClip() {
#endif
}
void OpenGLRenderer::renderGlop(const Glop& glop) {
if (mState.getDirtyClip()) {
if (mRenderState.scissor().isEnabled()) {
setScissorFromClip();
}
setStencilFromClip();
}
mRenderState.render(glop);
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
}
///////////////////////////////////////////////////////////////////////////////
// Drawing commands
///////////////////////////////////////////////////////////////////////////////
@@ -1601,9 +1613,9 @@ void OpenGLRenderer::setupDraw(bool clearLayer) {
// Enable debug highlight when what we're about to draw is tested against
// the stencil buffer and if stencil highlight debugging is on
mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
mRenderState.stencil().isTestEnabled();
mDescription.hasDebugHighlight = !mCaches.debugOverdraw
&& mCaches.debugStencilClip == Caches::kStencilShowHighlight
&& mRenderState.stencil().isTestEnabled();
}
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1663,7 +1675,7 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
if (shader != nullptr) {
SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
}
}
@@ -1784,7 +1796,8 @@ void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignore
mModelViewMatrix.load(modelViewWithoutTransform);
}
SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
mCaches.extensions(), *shader);
}
void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
@@ -1978,7 +1991,7 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top,
// bitmaps get packed in the atlas
drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
GL_TRIANGLE_STRIP, kMeshCount, ignoreTransform);
GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
}
/**
@@ -2132,7 +2145,7 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m
setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
setupDrawTexture(texture->id);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
@@ -2218,12 +2231,12 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, kMeshCount, ignoreTransform);
GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
} else {
drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint, texture->blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, kMeshCount, false, ignoreTransform);
GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
}
if (CC_UNLIKELY(useScaleTransform)) {
@@ -2333,17 +2346,33 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
return;
}
if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
Glop glop;
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
.setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
.setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
.setPaint(paint, currentSnapshot()->alpha)
.build();
renderGlop(glop);
return;
}
const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
Rect bounds(vertexBuffer.getBounds());
bounds.translate(translateX, translateY);
dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
int color = paint->getColor();
bool isAA = paint->isAntiAlias();
bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
setupDraw();
setupDrawNoTexture();
if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
setupDrawColor(color, ((color >> 24) & 0xFF) * writableSnapshot()->alpha);
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader(getShader(paint));
setupDrawBlending(paint, isAA);
@@ -2369,22 +2398,13 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
}
const VertexBuffer::Mode mode = vertexBuffer.getMode();
if (mode == VertexBuffer::kStandard) {
mRenderState.meshState().unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
} else if (mode == VertexBuffer::kOnePolyRingShadow) {
mRenderState.meshState().bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT,
GL_UNSIGNED_SHORT, nullptr);
} else if (mode == VertexBuffer::kTwoPolyRingShadow) {
mRenderState.meshState().bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT,
GL_UNSIGNED_SHORT, nullptr);
} else if (mode == VertexBuffer::kIndices) {
if (meshFeatureFlags & VertexBuffer::kIndices) {
mRenderState.meshState().unbindIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
} else {
mRenderState.meshState().unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
}
if (isAA) {
@@ -2666,7 +2686,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
setupDrawShaderUniforms(getShader(paint));
setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
@@ -3100,7 +3120,7 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
setupDrawShaderUniforms(getShader(paint));
setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
// Same values used by Skia
@@ -3259,6 +3279,20 @@ void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
const SkPaint* paint, bool ignoreTransform) {
if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
Glop glop;
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
aBuilder.setMeshUnitQuad()
.setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
.setModelViewMapUnitToRect(Rect(left, top, right, bottom))
.setPaint(paint, currentSnapshot()->alpha)
.build();
renderGlop(glop);
return;
}
int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (getShader(paint)) {
@@ -3279,7 +3313,7 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawSimpleMesh();
glDrawArrays(GL_TRIANGLE_STRIP, 0, kMeshCount);
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
@@ -3306,11 +3340,11 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
texture->setFilter(GL_NEAREST, true);
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
paint, texture->blend, vertices, texCoords,
GL_TRIANGLE_STRIP, kMeshCount, false, true);
GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
} else {
texture->setFilter(getFilter(paint), true);
drawTextureMesh(left, top, right, bottom, texture->id, paint,
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kMeshCount);
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
}
if (texture->uvMapper) {
@@ -3405,7 +3439,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
ProgramDescription& description, bool swapSrcDst) {
if (writableSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
blend = true;
mDescription.hasRoundRectClip = true;
}
@@ -3420,7 +3454,7 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
// If the blend mode cannot be implemented using shaders, fall
// back to the default SrcOver blend mode instead
if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
description.framebufferMode = mode;
description.swapSrcDst = swapSrcDst;

View File

@@ -57,6 +57,7 @@ namespace android {
namespace uirenderer {
class DeferredDisplayState;
struct Glop;
class RenderState;
class RenderNode;
class TextSetupFunctor;
@@ -529,10 +530,11 @@ protected:
CanvasState mState;
Caches& mCaches;
Extensions& mExtensions; // TODO: move to RenderState
RenderState& mRenderState;
private:
void renderGlop(const Glop& glop);
/**
* Discards the content of the framebuffer if supported by the driver.
* This method should be called at the beginning of a frame to optimize

View File

@@ -783,6 +783,7 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
Rect bounds(path.getBounds());
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
template <class TYPE>
@@ -840,6 +841,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
// expand bounds from vertex coords to pixel data
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
@@ -890,6 +892,7 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa
// expand bounds from vertex coords to pixel data
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -102,7 +102,7 @@ typedef uint64_t programid;
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
enum ColorModifier {
enum ColorFilterMode {
kColorNone = 0,
kColorMatrix,
kColorBlend
@@ -148,7 +148,7 @@ struct ProgramDescription {
GLenum bitmapWrapT;
// Color operations
ColorModifier colorOp;
ColorFilterMode colorOp;
SkXfermode::Mode colorMode;
// Framebuffer blending (requires Extensions.hasFramebufferFetch())

View File

@@ -404,7 +404,8 @@ const char* gBlendOps[18] = {
// Constructors/destructors
///////////////////////////////////////////////////////////////////////////////
ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
ProgramCache::ProgramCache(Extensions& extensions)
: mHasES3(extensions.getMajorGlVersion() >= 3) {
}
ProgramCache::~ProgramCache() {

View File

@@ -40,7 +40,7 @@ namespace uirenderer {
*/
class ProgramCache {
public:
ProgramCache();
ProgramCache(Extensions& extensions);
~ProgramCache();
Program* get(const ProgramDescription& description);

View File

@@ -1,152 +0,0 @@
/*
* Copyright (C) 2013 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_QUERY_H
#define ANDROID_HWUI_QUERY_H
#include <GLES3/gl3.h>
#include "Extensions.h"
namespace android {
namespace uirenderer {
/**
* A Query instance can be used to perform occlusion queries. If the device
* does not support occlusion queries, the result of a query will always be
* 0 and the result will always be marked available.
*
* To run an occlusion query successfully, you must start end end the query:
*
* Query query;
* query.begin();
* // execute OpenGL calls
* query.end();
* GLuint result = query.getResult();
*/
class Query {
public:
/**
* Possible query targets.
*/
enum Target {
/**
* Indicates if any sample passed the depth & stencil tests.
*/
kTargetSamples = GL_ANY_SAMPLES_PASSED,
/**
* Indicates if any sample passed the depth & stencil tests.
* The implementation may choose to use a less precise version
* of the test, potentially resulting in false positives.
*/
kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
};
/**
* Creates a new query with the specified target. The default
* target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.)
*/
Query(Target target = kTargetSamples): mActive(false), mTarget(target),
mCanQuery(Extensions::getInstance().hasOcclusionQueries()),
mQuery(0) {
}
~Query() {
if (mQuery) {
glDeleteQueries(1, &mQuery);
}
}
/**
* Begins the query. If the query has already begun or if the device
* does not support occlusion queries, calling this method as no effect.
* After calling this method successfully, the query is marked active.
*/
void begin() {
if (!mActive && mCanQuery) {
if (!mQuery) {
glGenQueries(1, &mQuery);
}
glBeginQuery(mTarget, mQuery);
mActive = true;
}
}
/**
* Ends the query. If the query has already begun or if the device
* does not support occlusion queries, calling this method as no effect.
* After calling this method successfully, the query is marked inactive.
*/
void end() {
if (mQuery && mActive) {
glEndQuery(mTarget);
mActive = false;
}
}
/**
* Returns true if the query is active, false otherwise.
*/
bool isActive() {
return mActive;
}
/**
* Returns true if the result of the query is available,
* false otherwise. Calling getResult() before the result
* is available may result in the calling thread being blocked.
* If the device does not support queries, this method always
* returns true.
*/
bool isResultAvailable() {
if (!mQuery) return true;
GLuint result;
glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result);
return result == GL_TRUE;
}
/**
* Returns the result of the query. If the device does not
* support queries this method will return 0.
*
* Calling this method implicitely calls end() if the query
* is currently active.
*/
GLuint getResult() {
if (!mQuery) return 0;
end();
GLuint result;
glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result);
return result;
}
private:
bool mActive;
GLenum mTarget;
bool mCanQuery;
GLuint mQuery;
}; // class Query
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_QUERY_H

View File

@@ -113,33 +113,6 @@ void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
#endif
}
void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
int currentIndex = 0;
const int rays = SHADOW_RAY_COUNT;
// For the penumbra area.
for (int layer = 0; layer < 2; layer ++) {
int baseIndex = layer * rays;
for (int i = 0; i < rays; i++) {
shadowIndices[currentIndex++] = i + baseIndex;
shadowIndices[currentIndex++] = rays + i + baseIndex;
}
// To close the loop, back to the ray 0.
shadowIndices[currentIndex++] = 0 + baseIndex;
// Note this is the same as the first index of next layer loop.
shadowIndices[currentIndex++] = rays + baseIndex;
}
#if DEBUG_SHADOW
if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
ALOGW("vertex index count is wrong. current %d, expected %d",
currentIndex, MAX_SHADOW_INDEX_COUNT);
}
for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
}
#endif
}
/**
* Calculate the centroid of a 2d polygon.
*

View File

@@ -78,8 +78,6 @@ public:
const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
static void generateShadowIndices(uint16_t* shadowIndices);
static Vector2 centroid2d(const Vector2* poly, int polyLength);
static bool isClockwise(const Vector2* polygon, int len);

View File

@@ -1031,7 +1031,7 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Spot Vertex Buffer");
ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Spot Index Buffer");
shadowTriangleStrip.setMode(VertexBuffer::kIndices);
shadowTriangleStrip.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
shadowTriangleStrip.computeBounds<AlphaVertex>();
}

View File

@@ -38,10 +38,12 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
TextureCache::TextureCache():
mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE), mAssetAtlas(nullptr) {
TextureCache::TextureCache()
: mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
, mSize(0)
, mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE))
, mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE)
, mAssetAtlas(nullptr) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting texture cache size to %sMB", property);
@@ -59,20 +61,6 @@ TextureCache::TextureCache():
DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
}
init();
}
TextureCache::TextureCache(uint32_t maxByteSize):
mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize), mAssetAtlas(nullptr) {
init();
}
TextureCache::~TextureCache() {
mCache.clear();
}
void TextureCache::init() {
mCache.setOnEntryRemovedListener(this);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -81,6 +69,10 @@ void TextureCache::init() {
mDebugEnabled = readDebugLevel() & kDebugCaches;
}
TextureCache::~TextureCache() {
mCache.clear();
}
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
@@ -280,7 +272,7 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
// We could also enable mipmapping if both bitmap dimensions are powers
// of 2 but we'd have to deal with size changes. Let's keep this simple
const bool canMipMap = Extensions::getInstance().hasNPot();
const bool canMipMap = Caches::getInstance().extensions().hasNPot();
// If the texture had mipmap enabled but not anymore,
// force a glTexImage2D to discard the mipmap levels
@@ -355,7 +347,8 @@ void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
const bool useStride = stride != width
&& Caches::getInstance().extensions().hasUnpackRowLength();
if ((stride == width) || useStride) {
if (useStride) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);

View File

@@ -52,10 +52,9 @@ class AssetAtlas;
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
class TextureCache: public OnEntryRemoved<uint32_t, Texture*> {
class TextureCache : public OnEntryRemoved<uint32_t, Texture*> {
public:
TextureCache();
TextureCache(uint32_t maxByteSize);
~TextureCache();
/**
@@ -146,8 +145,6 @@ private:
void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
void init();
LruCache<uint32_t, Texture*> mCache;
uint32_t mSize;

View File

@@ -24,11 +24,10 @@ namespace uirenderer {
class VertexBuffer {
public:
enum Mode {
kStandard = 0,
kOnePolyRingShadow = 1,
kTwoPolyRingShadow = 2,
kIndices = 3
enum MeshFeatureFlags {
kNone = 0,
kAlpha = 1 << 0,
kIndices = 1 << 1,
};
VertexBuffer()
@@ -39,7 +38,7 @@ public:
, mAllocatedVertexCount(0)
, mAllocatedIndexCount(0)
, mByteCount(0)
, mMode(kStandard)
, mMeshFeatureFlags(kNone)
, mReallocBuffer(nullptr)
, mCleanupMethod(nullptr)
, mCleanupIndexMethod(nullptr)
@@ -135,10 +134,12 @@ public:
void updateVertexCount(unsigned int newCount) {
mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
}
Mode getMode() const { return mMode; }
MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
void setMeshFeatureFlags(int flags) {
mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
}
void setBounds(Rect bounds) { mBounds = bounds; }
void setMode(Mode mode) { mMode = mode; }
template <class TYPE>
void createDegenerateSeparators(int allocSize) {
@@ -166,7 +167,7 @@ private:
unsigned int mAllocatedIndexCount;
unsigned int mByteCount;
Mode mMode;
MeshFeatureFlags mMeshFeatureFlags;
void* mReallocBuffer; // used for multi-allocation

View File

@@ -120,7 +120,7 @@ CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint3
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
// With OpenGL ES 2.0 we have to upload entire stripes instead.
mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength();
}
CacheTexture::~CacheTexture() {

View File

@@ -127,6 +127,10 @@ void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
}
}
void Blend::dump() {
ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode);
}
} /* namespace uirenderer */
} /* namespace android */

View File

@@ -35,6 +35,8 @@ public:
static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst);
void setFactors(GLenum src, GLenum dst);
void dump();
private:
Blend();
void invalidate();

View File

@@ -23,22 +23,20 @@ namespace android {
namespace uirenderer {
MeshState::MeshState()
: mCurrentPositionPointer(this)
: mCurrentIndicesBuffer(0)
, mCurrentPixelBuffer(0)
, mCurrentPositionPointer(this)
, mCurrentPositionStride(0)
, mCurrentTexCoordsPointer(this)
, mCurrentTexCoordsStride(0)
, mTexCoordsArrayEnabled(false) {
, mTexCoordsArrayEnabled(false)
, mQuadListIndices(0) {
glGenBuffers(1, &mUnitQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
mCurrentBuffer = mUnitQuadBuffer;
mCurrentIndicesBuffer = 0;
mCurrentPixelBuffer = 0;
mQuadListIndices = 0;
mShadowStripsIndices = 0;
// position attribute always enabled
glEnableVertexAttribArray(Program::kBindingPosition);
@@ -50,9 +48,10 @@ MeshState::~MeshState() {
glDeleteBuffers(1, &mQuadListIndices);
mQuadListIndices = 0;
}
glDeleteBuffers(1, &mShadowStripsIndices);
mShadowStripsIndices = 0;
void MeshState::dump() {
ALOGD("MeshState vertices: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
}
///////////////////////////////////////////////////////////////////////////////
@@ -65,18 +64,17 @@ bool MeshState::bindMeshBuffer() {
bool MeshState::bindMeshBuffer(GLuint buffer) {
if (!buffer) buffer = mUnitQuadBuffer;
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
mCurrentBuffer = buffer;
return true;
}
return false;
return bindMeshBufferInternal(buffer);
}
bool MeshState::unbindMeshBuffer() {
if (mCurrentBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
mCurrentBuffer = 0;
return bindMeshBufferInternal(0);
}
bool MeshState::bindMeshBufferInternal(GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
mCurrentBuffer = buffer;
return true;
}
return false;
@@ -163,20 +161,6 @@ bool MeshState::bindQuadIndicesBuffer() {
return bindIndicesBufferInternal(mQuadListIndices);
}
bool MeshState::bindShadowIndicesBuffer() {
if (!mShadowStripsIndices) {
std::unique_ptr<uint16_t[]> shadowIndices(new uint16_t[MAX_SHADOW_INDEX_COUNT]);
ShadowTessellator::generateShadowIndices(shadowIndices.get());
glGenBuffers(1, &mShadowStripsIndices);
bool force = bindIndicesBufferInternal(mShadowStripsIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
shadowIndices.get(), GL_STATIC_DRAW);
return force;
}
return bindIndicesBufferInternal(mShadowStripsIndices);
}
bool MeshState::unbindIndicesBuffer() {
if (mCurrentIndicesBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

View File

@@ -47,7 +47,7 @@ const GLsizei kMeshTextureOffset = 2 * sizeof(float);
const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
const GLsizei kVertexAAWidthOffset = 2 * sizeof(float);
const GLsizei kVertexAALengthOffset = 3 * sizeof(float);
const GLsizei kMeshCount = 4;
const GLsizei kUnitQuadCount = 4;
class MeshState {
private:
@@ -55,6 +55,7 @@ private:
public:
~MeshState();
void dump();
///////////////////////////////////////////////////////////////////////////////
// Buffer objects
///////////////////////////////////////////////////////////////////////////////
@@ -107,7 +108,6 @@ public:
* gMaxNumberOfQuads quads.
*/
bool bindQuadIndicesBuffer();
bool bindShadowIndicesBuffer();
bool unbindIndicesBuffer();
///////////////////////////////////////////////////////////////////////////////
@@ -116,9 +116,9 @@ public:
GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
private:
MeshState();
bool bindMeshBufferInternal(const GLuint buffer);
bool bindIndicesBufferInternal(const GLuint buffer);
// VBO to draw with
GLuint mUnitQuadBuffer;
GLuint mCurrentBuffer;
@@ -134,7 +134,6 @@ private:
// Global index buffer
GLuint mQuadListIndices;
GLuint mShadowStripsIndices;
};
} /* namespace uirenderer */

View File

@@ -17,6 +17,7 @@
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
#include "utils/GLUtils.h"
namespace android {
namespace uirenderer {
@@ -213,18 +214,41 @@ void RenderState::render(const Glop& glop) {
const Glop::Mesh& mesh = glop.mesh;
const Glop::Fill& shader = glop.fill;
// --------------------------------------------
// ---------- Shader + uniform setup ----------
// --------------------------------------------
mCaches->setProgram(shader.program);
Glop::Fill::Color color = shader.color;
Glop::FloatColor color = shader.color;
shader.program->setColor(color.r, color.g, color.b, color.a);
shader.program->set(glop.transform.ortho,
glop.transform.modelView,
glop.transform.canvas,
glop.transform.offset);
glop.transform.fudgingOffset);
if (glop.fill.filterMode == ProgramDescription::kColorBlend) {
const Glop::FloatColor& color = glop.fill.filter.color;
glUniform4f(mCaches->program().getUniform("colorBlend"),
color.r, color.g, color.b, color.a);
} else if (glop.fill.filterMode == ProgramDescription::kColorMatrix) {
glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
glop.fill.filter.matrix.matrix);
glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
glop.fill.filter.matrix.vector);
}
// --------------------------------
// ---------- Mesh setup ----------
// --------------------------------
// vertices
bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
|| (mesh.vertices != nullptr);
meshState().bindPositionVertexPointer(force, mesh.vertices, mesh.stride);
// indices
meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
if (glop.mesh.vertexFlags & kTextureCoord_Attrib) {
// TODO: support textures
LOG_ALWAYS_FATAL("textures not yet supported");
@@ -232,40 +256,42 @@ void RenderState::render(const Glop& glop) {
meshState().disableTexCoordsVertexArray();
}
if (glop.mesh.vertexFlags & kColor_Attrib) {
LOG_ALWAYS_FATAL("color attribute not yet supported");
LOG_ALWAYS_FATAL("color vertex attribute not yet supported");
// TODO: enable color, disable when done
}
int alphaSlot = -1;
if (glop.mesh.vertexFlags & kAlpha_Attrib) {
LOG_ALWAYS_FATAL("alpha attribute not yet supported");
// TODO: enable alpha attribute, disable when done
const void* alphaCoords = ((const GLbyte*) glop.mesh.vertices) + kVertexAlphaOffset;
alphaSlot = shader.program->getAttrib("vtxAlpha");
glEnableVertexAttribArray(alphaSlot);
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
}
/**
* Hard-coded vertex assumptions:
* - required
* - xy floats
* - 0 offset
* - in VBO
*/
bool force = meshState().bindMeshBuffer(mesh.vertexBufferObject);
meshState().bindPositionVertexPointer(force, nullptr, mesh.stride);
/**
* Hard-coded index assumptions:
* - optional
* - 0 offset
* - in IBO
*/
meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
// ------------------------------------
// ---------- GL state setup ----------
// ------------------------------------
blend().setFactors(glop.blend.src, glop.blend.dst);
if (mesh.indexBufferObject) {
glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount, GL_UNSIGNED_BYTE, nullptr);
// ------------------------------------
// ---------- GL state setup ----------
// ------------------------------------
if (mesh.indexBufferObject || mesh.indices) {
glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount,
GL_UNSIGNED_SHORT, mesh.indices);
} else {
glDrawArrays(GL_TRIANGLE_STRIP, 0, glop.mesh.vertexCount);
glDrawArrays(glop.mesh.primitiveMode, 0, glop.mesh.vertexCount);
}
if (glop.mesh.vertexFlags & kAlpha_Attrib) {
glDisableVertexAttribArray(alphaSlot);
}
}
void RenderState::dump() {
blend().dump();
meshState().dump();
scissor().dump();
stencil().dump();
}
} /* namespace uirenderer */

View File

@@ -91,6 +91,8 @@ public:
MeshState& meshState() { return *mMeshState; }
Scissor& scissor() { return *mScissor; }
Stencil& stencil() { return *mStencil; }
void dump();
private:
friend class renderthread::RenderThread;
friend class Caches;
@@ -99,9 +101,6 @@ private:
void resumeFromFunctorInvoke();
void assertOnGLThread();
void setupVertexAttributes(const Glop& glop);
void tearDownVertexAttributes(const Glop& glop);
RenderState(renderthread::RenderThread& thread);
~RenderState();

View File

@@ -15,6 +15,8 @@
*/
#include "renderstate/Scissor.h"
#include <utils/Log.h>
namespace android {
namespace uirenderer {
@@ -79,6 +81,11 @@ void Scissor::invalidate() {
reset();
}
void Scissor::dump() {
ALOGD("Scissor: enabled %d, %d %d %d %d",
mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
}
} /* namespace uirenderer */
} /* namespace android */

View File

@@ -29,6 +29,7 @@ public:
bool set(GLint x, GLint y, GLint width, GLint height);
void reset();
bool isEnabled() { return mEnabled; }
void dump();
private:
Scissor();
void invalidate();

View File

@@ -14,10 +14,12 @@
* limitations under the License.
*/
#include "renderstate/Stencil.h"
#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
#include "Properties.h"
#include "renderstate/Stencil.h"
#include <GLES2/gl2ext.h>
@@ -42,7 +44,7 @@ uint8_t Stencil::getStencilSize() {
GLenum Stencil::getSmallestStencilFormat() {
#if !DEBUG_STENCIL
const Extensions& extensions = Extensions::getInstance();
const Extensions& extensions = Caches::getInstance().extensions();
if (extensions.has1BitStencil()) {
return GL_STENCIL_INDEX1_OES;
} else if (extensions.has4BitStencil()) {
@@ -123,5 +125,9 @@ void Stencil::disable() {
}
}
void Stencil::dump() {
ALOGD("Stencil: state %d", mState);
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -98,6 +98,8 @@ public:
return mState == kTest;
}
void dump();
private:
void enable();

View File

@@ -201,6 +201,45 @@ private:
}
};
class OvalAnimation : public TreeContentAnimation {
public:
sp<RenderNode> card;
void createContent(int width, int height, DisplayListRenderer* renderer) override {
android::uirenderer::Rect DUMMY;
renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
renderer->insertReorderBarrier(true);
card = createCard(40, 40, 200, 200);
renderer->drawRenderNode(card.get(), DUMMY, 0);
renderer->insertReorderBarrier(false);
}
void doFrame(int frameNr) override {
card->mutateStagingProperties().setTranslationX(frameNr);
card->mutateStagingProperties().setTranslationY(frameNr);
card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
sp<RenderNode> node = new RenderNode();
node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
DisplayListRenderer* renderer = startRecording(node.get());
renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xFF00FFFF);
renderer->drawOval(0, 0, width, height, paint);
endRecording(renderer, node.get());
return node;
}
};
struct cstr_cmp {
bool operator()(const char *a, const char *b) const {
return std::strcmp(a, b) < 0;
@@ -212,6 +251,7 @@ typedef void (*testProc)();
std::map<const char*, testProc, cstr_cmp> gTestMap {
{"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
{"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
{"oval", TreeContentAnimation::run<OvalAnimation> },
};
int main(int argc, char* argv[]) {

View File

@@ -52,6 +52,13 @@ public:
&& getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
}
static bool isBlendedShader(const SkShader* shader) {
if (shader == nullptr) {
return false;
}
return !shader->isOpaque();
}
static bool isBlendedColorFilter(const SkColorFilter* filter) {
if (filter == nullptr) {
return false;