Merge "Support for stencil clipping in layers"
This commit is contained in:
@@ -60,10 +60,18 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
|
||||
}
|
||||
|
||||
void BakedOpRenderer::endLayer() {
|
||||
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
|
||||
mRenderTarget.offscreenBuffer = nullptr;
|
||||
if (mRenderTarget.stencil) {
|
||||
// if stencil was used for clipping, detach it and return it to pool
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "glfbrb endlayer failed");
|
||||
mCaches.renderBufferCache.put(mRenderTarget.stencil);
|
||||
mRenderTarget.stencil = nullptr;
|
||||
}
|
||||
mRenderTarget.lastStencilClip = nullptr;
|
||||
|
||||
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
|
||||
mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
|
||||
|
||||
// Detach the texture from the FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
|
||||
@@ -75,7 +83,6 @@ void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& re
|
||||
LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
|
||||
mRenderState.bindFramebuffer(0);
|
||||
setViewport(width, height);
|
||||
mCaches.clearGarbage();
|
||||
|
||||
if (!mOpaque) {
|
||||
clearColorBuffer(repaintRect);
|
||||
@@ -113,6 +120,7 @@ void BakedOpRenderer::endFrame(const Rect& repaintRect) {
|
||||
mRenderState.stencil().disable();
|
||||
}
|
||||
|
||||
mCaches.clearGarbage();
|
||||
mCaches.pathCache.trim();
|
||||
mCaches.tessellationCache.trim();
|
||||
|
||||
@@ -232,28 +240,45 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
|
||||
mRenderState.scissor().setEnabled(clip != nullptr);
|
||||
if (clip) {
|
||||
mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
|
||||
if (CC_LIKELY(!Properties::debugOverdraw)) {
|
||||
// only modify stencil mode and content when it's not used for overdraw visualization
|
||||
if (CC_UNLIKELY(clip->mode != ClipMode::Rectangle)) {
|
||||
// NOTE: this pointer check is only safe for non-rect clips,
|
||||
// since rect clips may be created on the stack
|
||||
if (mRenderTarget.lastStencilClip != clip) {
|
||||
// Stencil needed, but current stencil isn't up to date
|
||||
mRenderTarget.lastStencilClip = clip;
|
||||
}
|
||||
|
||||
if (mRenderTarget.offscreenBuffer) {
|
||||
LOG_ALWAYS_FATAL("prepare layer stencil");
|
||||
}
|
||||
if (CC_LIKELY(!Properties::debugOverdraw)) {
|
||||
// only modify stencil mode and content when it's not used for overdraw visualization
|
||||
if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
|
||||
// NOTE: this pointer check is only safe for non-rect clips,
|
||||
// since rect clips may be created on the stack
|
||||
if (mRenderTarget.lastStencilClip != clip) {
|
||||
// Stencil needed, but current stencil isn't up to date
|
||||
mRenderTarget.lastStencilClip = clip;
|
||||
|
||||
if (clip->mode == ClipMode::RectangleList) {
|
||||
setupStencilRectList(clip);
|
||||
} else {
|
||||
setupStencilRegion(clip);
|
||||
}
|
||||
if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
|
||||
OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
|
||||
mRenderTarget.stencil = mCaches.renderBufferCache.get(
|
||||
Stencil::getLayerStencilFormat(),
|
||||
layer->texture.width, layer->texture.height);
|
||||
// stencil is bound + allocated - associate it with current FBO
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, mRenderTarget.stencil->getName());
|
||||
}
|
||||
|
||||
if (clip->mode == ClipMode::RectangleList) {
|
||||
setupStencilRectList(clip);
|
||||
} else {
|
||||
setupStencilRegion(clip);
|
||||
}
|
||||
} else {
|
||||
mRenderState.stencil().disable();
|
||||
// stencil is up to date - just need to ensure it's enabled (since an unclipped
|
||||
// or scissor-only clipped op may have been drawn, disabling the stencil)
|
||||
int incrementThreshold = 0;
|
||||
if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
|
||||
auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
|
||||
incrementThreshold = rectList.getTransformedRectanglesCount();
|
||||
}
|
||||
mRenderState.stencil().enableTest(incrementThreshold);
|
||||
}
|
||||
} else {
|
||||
// either scissor or no clip, so disable stencil test
|
||||
mRenderState.stencil().disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,12 +95,24 @@ private:
|
||||
// render target state - setup by start/end layer/frame
|
||||
// only valid to use in between start/end pairs.
|
||||
struct {
|
||||
// If not drawing to a layer: fbo = 0, offscreenBuffer = null,
|
||||
// Otherwise these refer to currently painting layer's state
|
||||
GLuint frameBufferId = 0;
|
||||
OffscreenBuffer* offscreenBuffer = nullptr;
|
||||
|
||||
// Used when drawing to a layer and using stencil clipping. otherwise null.
|
||||
RenderBuffer* stencil = nullptr;
|
||||
|
||||
// value representing the ClipRectList* or ClipRegion* currently stored in
|
||||
// the stencil of the current render target
|
||||
const ClipBase* lastStencilClip = nullptr;
|
||||
|
||||
// Size of renderable region in current render target - for layers, may not match actual
|
||||
// bounds of FBO texture. offscreenBuffer->texture has this information.
|
||||
uint32_t viewportWidth = 0;
|
||||
uint32_t viewportHeight = 0;
|
||||
|
||||
Matrix4 orthoMatrix;
|
||||
const ClipBase* lastStencilClip = nullptr;
|
||||
} mRenderTarget;
|
||||
|
||||
const LightInfo mLightInfo;
|
||||
|
||||
@@ -78,7 +78,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementC
|
||||
mOutGlop->mesh.vertices = {
|
||||
vbo,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, (const void*) kMeshTextureOffset, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.elementCount = elementCount;
|
||||
return *this;
|
||||
|
||||
@@ -391,9 +391,9 @@ struct LayerOp : RecordedOp {
|
||||
LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
|
||||
: SUPER_PAINTLESS(LayerOp)
|
||||
, layerHandle(layerHandle)
|
||||
, alpha(paint->getAlpha() / 255.0f)
|
||||
, alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
|
||||
, mode(PaintUtils::getXfermodeDirect(paint))
|
||||
, colorFilter(paint->getColorFilter())
|
||||
, colorFilter(paint ? paint->getColorFilter() : nullptr)
|
||||
, destroy(true) {}
|
||||
|
||||
LayerOp(RenderNode& node)
|
||||
|
||||
@@ -30,8 +30,6 @@ public:
|
||||
sp<RenderNode> card;
|
||||
void createContent(int width, int height, TestCanvas& canvas) override {
|
||||
canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
|
||||
canvas.insertReorderBarrier(true);
|
||||
|
||||
card = TestUtils::createNode(0, 0, 200, 400,
|
||||
[](RenderProperties& props, TestCanvas& canvas) {
|
||||
canvas.save(SkCanvas::kMatrixClip_SaveFlag);
|
||||
@@ -53,10 +51,12 @@ public:
|
||||
canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
|
||||
}
|
||||
canvas.restore();
|
||||
|
||||
// put on a layer, to test stencil attachment
|
||||
props.mutateLayerProperties().setType(LayerType::RenderLayer);
|
||||
props.setAlpha(0.9f);
|
||||
});
|
||||
canvas.drawRenderNode(card.get());
|
||||
|
||||
canvas.insertReorderBarrier(false);
|
||||
}
|
||||
void doFrame(int frameNr) override {
|
||||
int curFrame = frameNr % 150;
|
||||
|
||||
Reference in New Issue
Block a user