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:
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class Caches;
|
||||
class Extensions;
|
||||
class Program;
|
||||
|
||||
// Must be a power of two
|
||||
|
||||
@@ -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
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace uirenderer {
|
||||
*/
|
||||
class ProgramCache {
|
||||
public:
|
||||
ProgramCache();
|
||||
ProgramCache(Extensions& extensions);
|
||||
~ProgramCache();
|
||||
|
||||
Program* get(const ProgramDescription& description);
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -98,6 +98,8 @@ public:
|
||||
return mState == kTest;
|
||||
}
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
void enable();
|
||||
|
||||
|
||||
@@ -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[]) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user