Define clear regions in terms of GrFixedClip
Updates clear APIs to take GrFixedClip instead of a rectangle. This will allow us to use window rectangles with clears. Removes stencil knobs from GrFixedClip. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2262473003 Review-Url: https://codereview.chromium.org/2262473003
This commit is contained in:
parent
dc43898bbb
commit
29df76096f
@ -25,6 +25,7 @@ class GrDrawContextPriv;
|
||||
class GrDrawPathBatchBase;
|
||||
class GrDrawingManager;
|
||||
class GrDrawTarget;
|
||||
class GrFixedClip;
|
||||
class GrPaint;
|
||||
class GrPathProcessor;
|
||||
class GrPipelineBuilder;
|
||||
@ -353,6 +354,8 @@ private:
|
||||
friend class GrStencilAndCoverPathRenderer; // for access to drawBatch
|
||||
friend class GrTessellatingPathRenderer; // for access to drawBatch
|
||||
|
||||
void internalClear(const GrFixedClip&, const GrColor, bool canIgnoreClip);
|
||||
|
||||
bool drawFilledDRRect(const GrClip& clip,
|
||||
const GrPaint& paint,
|
||||
const SkMatrix& viewMatrix,
|
||||
|
@ -489,10 +489,12 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
|
||||
// The texture may be larger than necessary, this rect represents the part of the texture
|
||||
// we populate with a rasterization of the clip.
|
||||
SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
|
||||
GrFixedClip clip(maskSpaceIBounds);
|
||||
|
||||
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
|
||||
// clear the part that we care about.
|
||||
dc->clear(&maskSpaceIBounds, InitialState::kAllIn == reducedClip.initialState() ? -1 : 0, true);
|
||||
GrColor initialCoverage = InitialState::kAllIn == reducedClip.initialState() ? -1 : 0;
|
||||
dc->drawContextPriv().clear(clip, initialCoverage, true);
|
||||
|
||||
// Set the matrix so that rendered clip elements are transformed to mask space from clip
|
||||
// space.
|
||||
@ -509,8 +511,6 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
|
||||
SkRegion::Op op = element->getOp();
|
||||
bool invert = element->isInverseFilled();
|
||||
if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
|
||||
GrFixedClip clip(maskSpaceIBounds);
|
||||
|
||||
// draw directly into the result with the stencil set to make the pixels affected
|
||||
// by the clip shape be non-zero.
|
||||
static constexpr GrUserStencilSettings kStencilInElement(
|
||||
@ -549,7 +549,7 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
|
||||
paint.setAntiAlias(element->isAA());
|
||||
paint.setCoverageSetOpXPFactory(op, false);
|
||||
|
||||
draw_element(dc.get(), GrNoClip(), paint, translate, element);
|
||||
draw_element(dc.get(), clip, paint, translate, element);
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,8 +560,37 @@ sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
|
||||
// (as opposed to canvas) coordinates
|
||||
// Create a 1-bit clip mask in the stencil buffer.
|
||||
|
||||
class StencilClip final : public GrClip {
|
||||
public:
|
||||
StencilClip(const SkIRect& scissorRect) : fFixedClip(scissorRect) {}
|
||||
const GrFixedClip& fixedClip() const { return fFixedClip; }
|
||||
|
||||
private:
|
||||
bool quickContains(const SkRect&) const final {
|
||||
return false;
|
||||
}
|
||||
void getConservativeBounds(int width, int height, SkIRect* devResult, bool* iior) const final {
|
||||
fFixedClip.getConservativeBounds(width, height, devResult, iior);
|
||||
}
|
||||
bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const final {
|
||||
return false;
|
||||
}
|
||||
bool apply(GrContext* context, GrDrawContext* drawContext, bool useHWAA,
|
||||
bool hasUserStencilSettings, GrAppliedClip* out) const final {
|
||||
if (!fFixedClip.apply(context, drawContext, useHWAA, hasUserStencilSettings, out)) {
|
||||
return false;
|
||||
}
|
||||
out->addStencilClip();
|
||||
return true;
|
||||
}
|
||||
|
||||
GrFixedClip fFixedClip;
|
||||
|
||||
typedef GrClip INHERITED;
|
||||
};
|
||||
|
||||
bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
GrDrawContext* drawContext,
|
||||
const GrReducedClip& reducedClip,
|
||||
@ -590,10 +619,10 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
// We set the current clip to the bounds so that our recursive draws are scissored to them.
|
||||
SkIRect stencilSpaceIBounds(reducedClip.ibounds());
|
||||
stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
|
||||
GrFixedClip clip(stencilSpaceIBounds);
|
||||
StencilClip stencilClip(stencilSpaceIBounds);
|
||||
|
||||
bool insideClip = InitialState::kAllIn == reducedClip.initialState();
|
||||
drawContext->drawContextPriv().clearStencilClip(stencilSpaceIBounds, insideClip);
|
||||
bool initialState = InitialState::kAllIn == reducedClip.initialState();
|
||||
drawContext->drawContextPriv().clearStencilClip(stencilClip.fixedClip(), initialState);
|
||||
|
||||
// walk through each clip element and perform its set op
|
||||
// with the existing clip.
|
||||
@ -602,8 +631,6 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
bool useHWAA = element->isAA() && drawContext->isStencilBufferMultisampled();
|
||||
|
||||
bool fillInverted = false;
|
||||
// enabled at bottom of loop
|
||||
clip.disableStencilClip();
|
||||
|
||||
// This will be used to determine whether the clip shape can be rendered into the
|
||||
// stencil with arbitrary stencil settings.
|
||||
@ -663,7 +690,8 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
0xffff>()
|
||||
);
|
||||
if (Element::kRect_Type == element->getType()) {
|
||||
drawContext->drawContextPriv().stencilRect(clip, &kDrawToStencil, useHWAA,
|
||||
drawContext->drawContextPriv().stencilRect(stencilClip.fixedClip(),
|
||||
&kDrawToStencil, useHWAA,
|
||||
viewMatrix, element->getRect());
|
||||
} else {
|
||||
if (!clipPath.isEmpty()) {
|
||||
@ -678,7 +706,7 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
args.fPaint = &paint;
|
||||
args.fUserStencilSettings = &kDrawToStencil;
|
||||
args.fDrawContext = drawContext;
|
||||
args.fClip = &clip;
|
||||
args.fClip = &stencilClip.fixedClip();
|
||||
args.fViewMatrix = &viewMatrix;
|
||||
args.fShape = &shape;
|
||||
args.fAntiAlias = false;
|
||||
@ -688,7 +716,7 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
GrPathRenderer::StencilPathArgs args;
|
||||
args.fResourceProvider = context->resourceProvider();
|
||||
args.fDrawContext = drawContext;
|
||||
args.fClip = &clip;
|
||||
args.fClip = &stencilClip.fixedClip();
|
||||
args.fViewMatrix = &viewMatrix;
|
||||
args.fIsAA = element->isAA();
|
||||
args.fShape = &shape;
|
||||
@ -698,16 +726,13 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
}
|
||||
}
|
||||
|
||||
// Just enable stencil clip. The passes choose whether or not they will actually use it.
|
||||
clip.enableStencilClip();
|
||||
|
||||
// now we modify the clip bit by rendering either the clip
|
||||
// element directly or a bounding rect of the entire clip.
|
||||
for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
|
||||
if (drawDirectToClip) {
|
||||
if (Element::kRect_Type == element->getType()) {
|
||||
drawContext->drawContextPriv().stencilRect(clip, *pass, useHWAA, viewMatrix,
|
||||
element->getRect());
|
||||
drawContext->drawContextPriv().stencilRect(stencilClip, *pass, useHWAA,
|
||||
viewMatrix, element->getRect());
|
||||
} else {
|
||||
GrShape shape(clipPath, GrStyle::SimpleFill());
|
||||
GrPaint paint;
|
||||
@ -718,7 +743,7 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
args.fPaint = &paint;
|
||||
args.fUserStencilSettings = *pass;
|
||||
args.fDrawContext = drawContext;
|
||||
args.fClip = &clip;
|
||||
args.fClip = &stencilClip;
|
||||
args.fViewMatrix = &viewMatrix;
|
||||
args.fShape = &shape;
|
||||
args.fAntiAlias = false;
|
||||
@ -728,7 +753,8 @@ bool GrClipStackClip::CreateStencilClipMask(GrContext* context,
|
||||
} else {
|
||||
// The view matrix is setup to do clip space -> stencil space translation, so
|
||||
// draw rect in clip space.
|
||||
drawContext->drawContextPriv().stencilRect(clip, *pass, false, viewMatrix,
|
||||
drawContext->drawContextPriv().stencilRect(stencilClip, *pass,
|
||||
false, viewMatrix,
|
||||
SkRect::Make(reducedClip.ibounds()));
|
||||
}
|
||||
}
|
||||
|
@ -196,45 +196,55 @@ void GrDrawContext::clear(const SkIRect* rect,
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear");
|
||||
|
||||
AutoCheckFlush acf(fDrawingManager);
|
||||
this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect);
|
||||
}
|
||||
|
||||
const SkIRect rtRect = SkIRect::MakeWH(this->width(), this->height());
|
||||
SkIRect clippedRect;
|
||||
bool isFull = false;
|
||||
if (!rect ||
|
||||
(canIgnoreRect && fContext->caps()->fullClearIsFree()) ||
|
||||
rect->contains(rtRect)) {
|
||||
rect = &rtRect;
|
||||
isFull = true;
|
||||
} else {
|
||||
clippedRect = *rect;
|
||||
if (!clippedRect.intersect(rtRect)) {
|
||||
return;
|
||||
}
|
||||
rect = &clippedRect;
|
||||
}
|
||||
void GrDrawContextPriv::clear(const GrFixedClip& clip,
|
||||
const GrColor color,
|
||||
bool canIgnoreClip) {
|
||||
ASSERT_SINGLE_OWNER_PRIV
|
||||
RETURN_IF_ABANDONED_PRIV
|
||||
SkDEBUGCODE(fDrawContext->validate();)
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clear");
|
||||
|
||||
AutoCheckFlush acf(fDrawContext->fDrawingManager);
|
||||
fDrawContext->internalClear(clip, color, canIgnoreClip);
|
||||
}
|
||||
|
||||
void GrDrawContext::internalClear(const GrFixedClip& clip,
|
||||
const GrColor color,
|
||||
bool canIgnoreClip) {
|
||||
bool isFull = !clip.scissorEnabled() ||
|
||||
(canIgnoreClip && fContext->caps()->fullClearIsFree()) ||
|
||||
clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
|
||||
|
||||
if (fContext->caps()->useDrawInsteadOfClear()) {
|
||||
// This works around a driver bug with clear by drawing a rect instead.
|
||||
// The driver will ignore a clear if it is the only thing rendered to a
|
||||
// target before the target is read.
|
||||
if (rect == &rtRect) {
|
||||
SkRect clearRect = SkRect::MakeIWH(this->width(), this->height());
|
||||
if (isFull) {
|
||||
this->discard();
|
||||
} else if (!clearRect.intersect(SkRect::Make(clip.scissorRect()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
GrPaint paint;
|
||||
paint.setColor4f(GrColor4f::FromGrColor(color));
|
||||
paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode));
|
||||
|
||||
this->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::Make(*rect));
|
||||
this->drawRect(clip, paint, SkMatrix::I(), clearRect);
|
||||
} else if (isFull) {
|
||||
this->getDrawTarget()->fullClear(this->accessRenderTarget(), color);
|
||||
} else {
|
||||
sk_sp<GrBatch> batch(GrClearBatch::Make(*rect, color, this->accessRenderTarget()));
|
||||
sk_sp<GrBatch> batch(GrClearBatch::Make(clip, color, this->accessRenderTarget()));
|
||||
if (!batch) {
|
||||
return;
|
||||
}
|
||||
this->getDrawTarget()->addBatch(std::move(batch));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GrDrawContext::drawPaint(const GrClip& clip,
|
||||
const GrPaint& origPaint,
|
||||
const SkMatrix& viewMatrix) {
|
||||
@ -543,14 +553,14 @@ void GrDrawContext::drawRect(const GrClip& clip,
|
||||
this->internalDrawPath(clip, paint, viewMatrix, path, *style);
|
||||
}
|
||||
|
||||
void GrDrawContextPriv::clearStencilClip(const SkIRect& rect, bool insideClip) {
|
||||
void GrDrawContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
|
||||
ASSERT_SINGLE_OWNER_PRIV
|
||||
RETURN_IF_ABANDONED_PRIV
|
||||
SkDEBUGCODE(fDrawContext->validate();)
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clearStencilClip");
|
||||
|
||||
AutoCheckFlush acf(fDrawContext->fDrawingManager);
|
||||
fDrawContext->getDrawTarget()->clearStencilClip(rect, insideClip,
|
||||
fDrawContext->getDrawTarget()->clearStencilClip(clip, insideStencilMask,
|
||||
fDrawContext->accessRenderTarget());
|
||||
}
|
||||
|
||||
@ -561,7 +571,7 @@ void GrDrawContextPriv::stencilPath(const GrClip& clip,
|
||||
fDrawContext->getDrawTarget()->stencilPath(fDrawContext, clip, useHWAA, viewMatrix, path);
|
||||
}
|
||||
|
||||
void GrDrawContextPriv::stencilRect(const GrFixedClip& clip,
|
||||
void GrDrawContextPriv::stencilRect(const GrClip& clip,
|
||||
const GrUserStencilSettings* ss,
|
||||
bool useHWAA,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -580,7 +590,7 @@ void GrDrawContextPriv::stencilRect(const GrFixedClip& clip,
|
||||
fDrawContext->drawNonAAFilledRect(clip, paint, viewMatrix, rect, nullptr, nullptr, ss, useHWAA);
|
||||
}
|
||||
|
||||
bool GrDrawContextPriv::drawAndStencilRect(const GrFixedClip& clip,
|
||||
bool GrDrawContextPriv::drawAndStencilRect(const GrClip& clip,
|
||||
const GrUserStencilSettings* ss,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
@ -1232,7 +1242,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
||||
this->internalDrawPath(clip, paint, viewMatrix, path, style);
|
||||
}
|
||||
|
||||
bool GrDrawContextPriv::drawAndStencilPath(const GrFixedClip& clip,
|
||||
bool GrDrawContextPriv::drawAndStencilPath(const GrClip& clip,
|
||||
const GrUserStencilSettings* ss,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
|
@ -25,9 +25,11 @@ public:
|
||||
return fDrawContext->getDrawTarget()->instancedRendering();
|
||||
}
|
||||
|
||||
void clearStencilClip(const SkIRect& rect, bool insideClip);
|
||||
void clear(const GrFixedClip&, const GrColor, bool canIgnoreClip);
|
||||
|
||||
void stencilRect(const GrFixedClip& clip,
|
||||
void clearStencilClip(const GrFixedClip&, bool insideStencilMask);
|
||||
|
||||
void stencilRect(const GrClip& clip,
|
||||
const GrUserStencilSettings* ss,
|
||||
bool useHWAA,
|
||||
const SkMatrix& viewMatrix,
|
||||
@ -38,7 +40,7 @@ public:
|
||||
const SkMatrix& viewMatrix,
|
||||
const GrPath*);
|
||||
|
||||
bool drawAndStencilRect(const GrFixedClip&,
|
||||
bool drawAndStencilRect(const GrClip&,
|
||||
const GrUserStencilSettings*,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
@ -46,7 +48,7 @@ public:
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkRect&);
|
||||
|
||||
bool drawAndStencilPath(const GrFixedClip&,
|
||||
bool drawAndStencilPath(const GrClip&,
|
||||
const GrUserStencilSettings*,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
|
@ -459,9 +459,7 @@ void GrDrawTarget::fullClear(GrRenderTarget* renderTarget, GrColor color) {
|
||||
fLastFullClearBatch->setColor(color);
|
||||
return;
|
||||
}
|
||||
sk_sp<GrClearBatch> batch(GrClearBatch::Make(SkIRect::MakeWH(renderTarget->width(),
|
||||
renderTarget->height()),
|
||||
color, renderTarget));
|
||||
sk_sp<GrClearBatch> batch(GrClearBatch::Make(GrFixedClip::Disabled(), color, renderTarget));
|
||||
if (batch.get() == this->recordBatch(batch.get(), batch->bounds())) {
|
||||
fLastFullClearBatch = batch.get();
|
||||
}
|
||||
@ -619,8 +617,10 @@ void GrDrawTarget::forwardCombine() {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrDrawTarget::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* rt) {
|
||||
GrBatch* batch = new GrClearStencilClipBatch(rect, insideClip, rt);
|
||||
void GrDrawTarget::clearStencilClip(const GrFixedClip& clip,
|
||||
bool insideStencilMask,
|
||||
GrRenderTarget* rt) {
|
||||
GrBatch* batch = new GrClearStencilClipBatch(clip, insideStencilMask, rt);
|
||||
this->recordBatch(batch, batch->bounds());
|
||||
batch->unref();
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ private:
|
||||
void addDependency(GrDrawTarget* dependedOn);
|
||||
|
||||
// Used only by drawContextPriv.
|
||||
void clearStencilClip(const SkIRect&, bool insideClip, GrRenderTarget*);
|
||||
void clearStencilClip(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*);
|
||||
|
||||
struct RecordedBatch {
|
||||
sk_sp<GrBatch> fBatch;
|
||||
|
@ -10,13 +10,6 @@
|
||||
#include "GrAppliedClip.h"
|
||||
#include "GrDrawContext.h"
|
||||
|
||||
bool GrFixedClip::quickContains(const SkRect& rect) const {
|
||||
if (fHasStencilClip) {
|
||||
return false;
|
||||
}
|
||||
return !fScissorState.enabled() || GrClip::IsInsideClip(fScissorState.rect(), rect);
|
||||
}
|
||||
|
||||
void GrFixedClip::getConservativeBounds(int width, int height, SkIRect* devResult,
|
||||
bool* isIntersectionOfRects) const {
|
||||
devResult->setXYWH(0, 0, width, height);
|
||||
@ -46,9 +39,10 @@ bool GrFixedClip::apply(GrContext*, GrDrawContext* drawContext, bool isHWAntiAli
|
||||
}
|
||||
}
|
||||
|
||||
if (fHasStencilClip) {
|
||||
out->addStencilClip();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const GrFixedClip& GrFixedClip::Disabled() {
|
||||
static const GrFixedClip disabled = GrFixedClip();
|
||||
return disabled;
|
||||
}
|
||||
|
@ -12,37 +12,30 @@
|
||||
#include "GrTypesPriv.h"
|
||||
|
||||
/**
|
||||
* GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the
|
||||
* stencil buffer itself, but can be configured to use whatever clip is already there.
|
||||
* GrFixedClip is a clip that gets implemented by fixed-function hardware.
|
||||
*/
|
||||
class GrFixedClip final : public GrClip {
|
||||
public:
|
||||
GrFixedClip() : fHasStencilClip(false) {}
|
||||
GrFixedClip(const SkIRect& scissorRect)
|
||||
: fScissorState(scissorRect)
|
||||
, fHasStencilClip(false) {}
|
||||
GrFixedClip() = default;
|
||||
explicit GrFixedClip(const SkIRect& scissorRect) : fScissorState(scissorRect) {}
|
||||
|
||||
void reset() {
|
||||
fScissorState.setDisabled();
|
||||
fHasStencilClip = false;
|
||||
const GrScissorState& scissorState() const { return fScissorState; }
|
||||
bool scissorEnabled() const { return fScissorState.enabled(); }
|
||||
const SkIRect& scissorRect() const { SkASSERT(scissorEnabled()); return fScissorState.rect(); }
|
||||
|
||||
void disableScissor() { fScissorState.setDisabled(); }
|
||||
|
||||
bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& irect) {
|
||||
return fScissorState.intersect(irect);
|
||||
}
|
||||
|
||||
void reset(const SkIRect& scissorRect) {
|
||||
fScissorState.set(scissorRect);
|
||||
fHasStencilClip = false;
|
||||
bool quickContains(const SkRect& rect) const final {
|
||||
return !fScissorState.enabled() || GrClip::IsInsideClip(fScissorState.rect(), rect);
|
||||
}
|
||||
|
||||
void enableStencilClip() { fHasStencilClip = true; }
|
||||
void disableStencilClip() { fHasStencilClip = false; }
|
||||
|
||||
bool quickContains(const SkRect&) const final;
|
||||
void getConservativeBounds(int width, int height, SkIRect* devResult,
|
||||
bool* isIntersectionOfRects) const final;
|
||||
|
||||
bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override {
|
||||
if (fHasStencilClip) {
|
||||
return false;
|
||||
}
|
||||
if (fScissorState.enabled()) {
|
||||
SkRect rect = SkRect::Make(fScissorState.rect());
|
||||
if (!rect.intersects(rtBounds)) {
|
||||
@ -55,12 +48,13 @@ public:
|
||||
return false;
|
||||
};
|
||||
|
||||
private:
|
||||
bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
|
||||
GrAppliedClip* out) const final;
|
||||
|
||||
static const GrFixedClip& Disabled();
|
||||
|
||||
private:
|
||||
GrScissorState fScissorState;
|
||||
bool fHasStencilClip;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "GrGpuCommandBuffer.h"
|
||||
|
||||
#include "GrCaps.h"
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrPrimitiveProcessor.h"
|
||||
#include "GrRenderTarget.h"
|
||||
@ -18,17 +19,19 @@ void GrGpuCommandBuffer::submit(const SkIRect& bounds) {
|
||||
this->onSubmit(bounds);
|
||||
}
|
||||
|
||||
void GrGpuCommandBuffer::clear(const SkIRect& rect, GrColor color, GrRenderTarget* renderTarget) {
|
||||
SkASSERT(renderTarget);
|
||||
SkASSERT(SkIRect::MakeWH(renderTarget->width(), renderTarget->height()).contains(rect));
|
||||
this->onClear(renderTarget, rect, color);
|
||||
void GrGpuCommandBuffer::clear(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt) {
|
||||
SkASSERT(rt);
|
||||
SkASSERT(!clip.scissorEnabled() ||
|
||||
(SkIRect::MakeWH(rt->width(), rt->height()).contains(clip.scissorRect()) &&
|
||||
SkIRect::MakeWH(rt->width(), rt->height()) != clip.scissorRect()));
|
||||
this->onClear(rt, clip, color);
|
||||
}
|
||||
|
||||
void GrGpuCommandBuffer::clearStencilClip(const SkIRect& rect,
|
||||
bool insideClip,
|
||||
GrRenderTarget* renderTarget) {
|
||||
SkASSERT(renderTarget);
|
||||
this->onClearStencilClip(renderTarget, rect, insideClip);
|
||||
void GrGpuCommandBuffer::clearStencilClip(const GrFixedClip& clip,
|
||||
bool insideStencilMask,
|
||||
GrRenderTarget* rt) {
|
||||
SkASSERT(rt);
|
||||
this->onClearStencilClip(rt, clip, insideStencilMask);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "GrColor.h"
|
||||
|
||||
class GrFixedClip;
|
||||
class GrGpu;
|
||||
class GrMesh;
|
||||
class GrPipeline;
|
||||
@ -65,9 +66,9 @@ public:
|
||||
/**
|
||||
* Clear the passed in render target. Ignores the draw state and clip.
|
||||
*/
|
||||
void clear(const SkIRect& rect, GrColor color, GrRenderTarget* renderTarget);
|
||||
void clear(const GrFixedClip&, GrColor, GrRenderTarget*);
|
||||
|
||||
void clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* renderTarget);
|
||||
void clearStencilClip(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*);
|
||||
/**
|
||||
* Discards the contents render target. nullptr indicates that the current render target should
|
||||
* be discarded.
|
||||
@ -86,9 +87,11 @@ private:
|
||||
int meshCount) = 0;
|
||||
|
||||
// overridden by backend-specific derived class to perform the clear.
|
||||
virtual void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) = 0;
|
||||
virtual void onClear(GrRenderTarget*, const GrFixedClip&, GrColor) = 0;
|
||||
|
||||
virtual void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) = 0;
|
||||
virtual void onClearStencilClip(GrRenderTarget*,
|
||||
const GrFixedClip&,
|
||||
bool insideStencilMask) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -185,7 +185,7 @@ public:
|
||||
struct StencilPathArgs {
|
||||
GrResourceProvider* fResourceProvider;
|
||||
GrDrawContext* fDrawContext;
|
||||
const GrFixedClip* fClip;
|
||||
const GrClip* fClip;
|
||||
const SkMatrix* fViewMatrix;
|
||||
bool fIsAA;
|
||||
const GrShape* fShape;
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "GrBatch.h"
|
||||
#include "GrBatchFlushState.h"
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuCommandBuffer.h"
|
||||
#include "GrRenderTarget.h"
|
||||
@ -18,8 +19,12 @@ class GrClearBatch final : public GrBatch {
|
||||
public:
|
||||
DEFINE_BATCH_CLASS_ID
|
||||
|
||||
static sk_sp<GrClearBatch> Make(const SkIRect& rect, GrColor color, GrRenderTarget* rt) {
|
||||
return sk_sp<GrClearBatch>(new GrClearBatch(rect, color, rt));
|
||||
static sk_sp<GrClearBatch> Make(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt) {
|
||||
sk_sp<GrClearBatch> batch(new GrClearBatch(clip, color, rt));
|
||||
if (!batch->renderTarget()) {
|
||||
return nullptr; // The clip did not contain any pixels within the render target.
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
const char* name() const override { return "Clear"; }
|
||||
@ -28,10 +33,12 @@ public:
|
||||
GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
|
||||
|
||||
SkString dumpInfo() const override {
|
||||
SkString string;
|
||||
string.printf("Color: 0x%08x, Rect [L: %d, T: %d, R: %d, B: %d], RT: %d",
|
||||
fColor, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
|
||||
fRenderTarget.get()->getUniqueID());
|
||||
SkString string("Scissor [");
|
||||
if (fClip.scissorEnabled()) {
|
||||
const SkIRect& r = fClip.scissorRect();
|
||||
string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom);
|
||||
}
|
||||
string.appendf("], Color: 0x%08x, RT: %d", fColor, fRenderTarget.get()->getUniqueID());
|
||||
string.append(INHERITED::dumpInfo());
|
||||
return string;
|
||||
}
|
||||
@ -39,12 +46,23 @@ public:
|
||||
void setColor(GrColor color) { fColor = color; }
|
||||
|
||||
private:
|
||||
GrClearBatch(const SkIRect& rect, GrColor color, GrRenderTarget* rt)
|
||||
GrClearBatch(const GrFixedClip& clip, GrColor color, GrRenderTarget* rt)
|
||||
: INHERITED(ClassID())
|
||||
, fRect(rect)
|
||||
, fColor(color)
|
||||
, fRenderTarget(rt) {
|
||||
this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo);
|
||||
, fClip(clip)
|
||||
, fColor(color) {
|
||||
SkIRect rtRect = SkIRect::MakeWH(rt->width(), rt->height());
|
||||
if (fClip.scissorEnabled()) {
|
||||
// Don't let scissors extend outside the RT. This may improve batching.
|
||||
if (!fClip.intersect(rtRect)) {
|
||||
return;
|
||||
}
|
||||
if (fClip.scissorRect() == rtRect) {
|
||||
fClip.disableScissor();
|
||||
}
|
||||
}
|
||||
this->setBounds(SkRect::Make(fClip.scissorEnabled() ? fClip.scissorRect() : rtRect),
|
||||
HasAABloat::kNo, IsZeroArea::kNo);
|
||||
fRenderTarget.reset(rt);
|
||||
}
|
||||
|
||||
bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
|
||||
@ -53,24 +71,31 @@ private:
|
||||
// same color.
|
||||
GrClearBatch* cb = t->cast<GrClearBatch>();
|
||||
SkASSERT(cb->fRenderTarget == fRenderTarget);
|
||||
if (cb->fRect.contains(fRect)) {
|
||||
fRect = cb->fRect;
|
||||
if (cb->contains(this)) {
|
||||
fClip = cb->fClip;
|
||||
this->replaceBounds(*t);
|
||||
fColor = cb->fColor;
|
||||
return true;
|
||||
} else if (cb->fColor == fColor && fRect.contains(cb->fRect)) {
|
||||
} else if (cb->fColor == fColor && this->contains(cb)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains(const GrClearBatch* that) const {
|
||||
// The constructor ensures that scissor gets disabled on any clip that fills the entire RT.
|
||||
return !fClip.scissorEnabled() ||
|
||||
(that->fClip.scissorEnabled() &&
|
||||
fClip.scissorRect().contains(that->fClip.scissorRect()));
|
||||
}
|
||||
|
||||
void onPrepare(GrBatchFlushState*) override {}
|
||||
|
||||
void onDraw(GrBatchFlushState* state) override {
|
||||
state->commandBuffer()->clear(fRect, fColor, fRenderTarget.get());
|
||||
state->commandBuffer()->clear(fClip, fColor, fRenderTarget.get());
|
||||
}
|
||||
|
||||
SkIRect fRect;
|
||||
GrFixedClip fClip;
|
||||
GrColor fColor;
|
||||
GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> fRenderTarget;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "GrBatch.h"
|
||||
#include "GrBatchFlushState.h"
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuCommandBuffer.h"
|
||||
#include "GrRenderTarget.h"
|
||||
@ -18,12 +19,14 @@ class GrClearStencilClipBatch final : public GrBatch {
|
||||
public:
|
||||
DEFINE_BATCH_CLASS_ID
|
||||
|
||||
GrClearStencilClipBatch(const SkIRect& rect, bool insideClip, GrRenderTarget* rt)
|
||||
GrClearStencilClipBatch(const GrFixedClip& clip, bool insideStencilMask, GrRenderTarget* rt)
|
||||
: INHERITED(ClassID())
|
||||
, fRect(rect)
|
||||
, fInsideClip(insideClip)
|
||||
, fClip(clip)
|
||||
, fInsideStencilMask(insideStencilMask)
|
||||
, fRenderTarget(rt) {
|
||||
this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo);
|
||||
const SkRect& bounds = fClip.scissorEnabled() ? SkRect::Make(fClip.scissorRect())
|
||||
: SkRect::MakeIWH(rt->width(), rt->height());
|
||||
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
|
||||
}
|
||||
|
||||
const char* name() const override { return "ClearStencilClip"; }
|
||||
@ -32,10 +35,12 @@ public:
|
||||
GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); }
|
||||
|
||||
SkString dumpInfo() const override {
|
||||
SkString string;
|
||||
string.printf("Rect [L: %d, T: %d, R: %d, B: %d], IC: %d, RT: %d",
|
||||
fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, fInsideClip,
|
||||
fRenderTarget.get()->getUniqueID());
|
||||
SkString string("Scissor [");
|
||||
if (fClip.scissorEnabled()) {
|
||||
const SkIRect& r = fClip.scissorRect();
|
||||
string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom);
|
||||
}
|
||||
string.appendf("], IC: %d, RT: %d", fInsideStencilMask, fRenderTarget.get()->getUniqueID());
|
||||
string.append(INHERITED::dumpInfo());
|
||||
return string;
|
||||
}
|
||||
@ -46,11 +51,11 @@ private:
|
||||
void onPrepare(GrBatchFlushState*) override {}
|
||||
|
||||
void onDraw(GrBatchFlushState* state) override {
|
||||
state->commandBuffer()->clearStencilClip(fRect, fInsideClip, fRenderTarget.get());
|
||||
state->commandBuffer()->clearStencilClip(fClip, fInsideStencilMask, fRenderTarget.get());
|
||||
}
|
||||
|
||||
SkIRect fRect;
|
||||
bool fInsideClip;
|
||||
const GrFixedClip fClip;
|
||||
const bool fInsideStencilMask;
|
||||
GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> fRenderTarget;
|
||||
|
||||
typedef GrBatch INHERITED;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "GrGLGpuCommandBuffer.h"
|
||||
#include "GrGLStencilAttachment.h"
|
||||
#include "GrGLTextureRenderTarget.h"
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrMesh.h"
|
||||
#include "GrPipeline.h"
|
||||
@ -2197,17 +2198,15 @@ void GrGLGpu::disableScissor() {
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLGpu::clear(const SkIRect& rect, GrColor color, GrRenderTarget* target) {
|
||||
void GrGLGpu::clear(const GrFixedClip& clip, GrColor color, GrRenderTarget* target) {
|
||||
this->handleDirtyContext();
|
||||
|
||||
// parent class should never let us get here with no RT
|
||||
SkASSERT(target);
|
||||
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
|
||||
|
||||
this->flushRenderTarget(glRT, &rect);
|
||||
GrScissorState scissorState;
|
||||
scissorState.set(rect);
|
||||
this->flushScissor(scissorState, glRT->getViewport(), glRT->origin());
|
||||
this->flushRenderTarget(glRT, clip.scissorEnabled() ? &clip.scissorRect() : nullptr);
|
||||
this->flushScissor(clip.scissorState(), glRT->getViewport(), glRT->origin());
|
||||
this->disableWindowRectangles();
|
||||
|
||||
GrGLfloat r, g, b, a;
|
||||
@ -2240,7 +2239,9 @@ void GrGLGpu::clearStencil(GrRenderTarget* target) {
|
||||
fHWStencilSettings.invalidate();
|
||||
}
|
||||
|
||||
void GrGLGpu::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* target) {
|
||||
void GrGLGpu::clearStencilClip(const GrFixedClip& clip,
|
||||
bool insideStencilMask,
|
||||
GrRenderTarget* target) {
|
||||
SkASSERT(target);
|
||||
this->handleDirtyContext();
|
||||
|
||||
@ -2261,7 +2262,7 @@ void GrGLGpu::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTar
|
||||
static const GrGLint clipStencilMask = ~0;
|
||||
#endif
|
||||
GrGLint value;
|
||||
if (insideClip) {
|
||||
if (insideStencilMask) {
|
||||
value = (1 << (stencilBitCount - 1));
|
||||
} else {
|
||||
value = 0;
|
||||
@ -2269,9 +2270,7 @@ void GrGLGpu::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTar
|
||||
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
|
||||
this->flushRenderTarget(glRT, &SkIRect::EmptyIRect());
|
||||
|
||||
GrScissorState scissorState;
|
||||
scissorState.set(rect);
|
||||
this->flushScissor(scissorState, glRT->getViewport(), glRT->origin());
|
||||
this->flushScissor(clip.scissorState(), glRT->getViewport(), glRT->origin());
|
||||
this->disableWindowRectangles();
|
||||
|
||||
GL_CALL(StencilMask((uint32_t) clipStencilMask));
|
||||
|
@ -105,12 +105,12 @@ public:
|
||||
// The GrGLGpuCommandBuffer does not buffer up draws before submitting them to the gpu.
|
||||
// Thus this is the implementation of the clear call for the corresponding passthrough function
|
||||
// on GrGLGpuCommandBuffer.
|
||||
void clear(const SkIRect& rect, GrColor color, GrRenderTarget* renderTarget);
|
||||
void clear(const GrFixedClip&, GrColor, GrRenderTarget*);
|
||||
|
||||
// The GrGLGpuCommandBuffer does not buffer up draws before submitting them to the gpu.
|
||||
// Thus this is the implementation of the clearStencil call for the corresponding passthrough
|
||||
// function on GrGLGpuCommandBuffer.
|
||||
void clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* renderTarget);
|
||||
void clearStencilClip(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*);
|
||||
|
||||
const GrGLContext* glContextForTesting() const override {
|
||||
return &this->glContext();
|
||||
|
@ -39,12 +39,14 @@ private:
|
||||
fGpu->draw(pipeline, primProc, mesh, meshCount);
|
||||
}
|
||||
|
||||
void onClear(GrRenderTarget* rt, const SkIRect& rect, GrColor color) override {
|
||||
fGpu->clear(rect, color, rt);
|
||||
void onClear(GrRenderTarget* rt, const GrFixedClip& clip, GrColor color) override {
|
||||
fGpu->clear(clip, color, rt);
|
||||
}
|
||||
|
||||
void onClearStencilClip(GrRenderTarget* rt, const SkIRect& rect, bool insideClip) override {
|
||||
fGpu->clearStencilClip(rect, insideClip, rt);
|
||||
void onClearStencilClip(GrRenderTarget* rt,
|
||||
const GrFixedClip& clip,
|
||||
bool insideStencilMask) override {
|
||||
fGpu->clearStencilClip(clip, insideStencilMask, rt);
|
||||
}
|
||||
|
||||
GrGLGpu* fGpu;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GrVkGpuCommandBuffer.h"
|
||||
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrMesh.h"
|
||||
#include "GrPipeline.h"
|
||||
#include "GrRenderTargetPriv.h"
|
||||
@ -166,8 +167,8 @@ void GrVkGpuCommandBuffer::discard(GrRenderTarget* target) {
|
||||
}
|
||||
|
||||
void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target,
|
||||
const SkIRect& rect,
|
||||
bool insideClip) {
|
||||
const GrFixedClip& clip,
|
||||
bool insideStencilMask) {
|
||||
SkASSERT(target);
|
||||
|
||||
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
|
||||
@ -182,7 +183,7 @@ void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target,
|
||||
|
||||
VkClearDepthStencilValue vkStencilColor;
|
||||
memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
|
||||
if (insideClip) {
|
||||
if (insideStencilMask) {
|
||||
vkStencilColor.stencil = (1 << (stencilBitCount - 1));
|
||||
} else {
|
||||
vkStencilColor.stencil = 0;
|
||||
@ -190,11 +191,15 @@ void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target,
|
||||
|
||||
VkClearRect clearRect;
|
||||
// Flip rect if necessary
|
||||
SkIRect vkRect = rect;
|
||||
|
||||
if (kBottomLeft_GrSurfaceOrigin == vkRT->origin()) {
|
||||
vkRect.fTop = vkRT->height() - rect.fBottom;
|
||||
vkRect.fBottom = vkRT->height() - rect.fTop;
|
||||
SkIRect vkRect;
|
||||
if (!clip.scissorEnabled()) {
|
||||
vkRect.setXYWH(0, 0, vkRT->width(), vkRT->height());
|
||||
} else if (kBottomLeft_GrSurfaceOrigin != vkRT->origin()) {
|
||||
vkRect = clip.scissorRect();
|
||||
} else {
|
||||
const SkIRect& scissor = clip.scissorRect();
|
||||
vkRect.setLTRB(scissor.fLeft, vkRT->height() - scissor.fBottom,
|
||||
scissor.fRight, vkRT->height() - scissor.fTop);
|
||||
}
|
||||
|
||||
clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
|
||||
@ -215,7 +220,7 @@ void GrVkGpuCommandBuffer::onClearStencilClip(GrRenderTarget* target,
|
||||
fIsEmpty = false;
|
||||
}
|
||||
|
||||
void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color) {
|
||||
void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const GrFixedClip& clip, GrColor color) {
|
||||
// parent class should never let us get here with no RT
|
||||
SkASSERT(target);
|
||||
|
||||
@ -224,7 +229,7 @@ void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const SkIRect& rect,
|
||||
|
||||
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
|
||||
|
||||
if (fIsEmpty && rect.width() == target->width() && rect.height() == target->height()) {
|
||||
if (fIsEmpty && !clip.scissorEnabled()) {
|
||||
// We will change the render pass to do a clear load instead
|
||||
GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
VK_ATTACHMENT_STORE_OP_STORE);
|
||||
@ -259,10 +264,15 @@ void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const SkIRect& rect,
|
||||
// We always do a sub rect clear with clearAttachments since we are inside a render pass
|
||||
VkClearRect clearRect;
|
||||
// Flip rect if necessary
|
||||
SkIRect vkRect = rect;
|
||||
if (kBottomLeft_GrSurfaceOrigin == vkRT->origin()) {
|
||||
vkRect.fTop = vkRT->height() - rect.fBottom;
|
||||
vkRect.fBottom = vkRT->height() - rect.fTop;
|
||||
SkIRect vkRect;
|
||||
if (!clip.scissorEnabled()) {
|
||||
vkRect.setXYWH(0, 0, vkRT->width(), vkRT->height());
|
||||
} else if (kBottomLeft_GrSurfaceOrigin != vkRT->origin()) {
|
||||
vkRect = clip.scissorRect();
|
||||
} else {
|
||||
const SkIRect& scissor = clip.scissorRect();
|
||||
vkRect.setLTRB(scissor.fLeft, vkRT->height() - scissor.fBottom,
|
||||
scissor.fRight, vkRT->height() - scissor.fTop);
|
||||
}
|
||||
clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
|
||||
clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
|
||||
|
@ -52,9 +52,9 @@ private:
|
||||
const GrMesh* mesh,
|
||||
int meshCount) override;
|
||||
|
||||
void onClear(GrRenderTarget* rt, const SkIRect& rect, GrColor color) override;
|
||||
void onClear(GrRenderTarget* rt, const GrFixedClip&, GrColor color) override;
|
||||
|
||||
void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override;
|
||||
void onClearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask) override;
|
||||
|
||||
const GrVkRenderPass* fRenderPass;
|
||||
GrVkSecondaryCommandBuffer* fCommandBuffer;
|
||||
|
Loading…
Reference in New Issue
Block a user