Implement dynamic MSAA on OpenGL
This is an initial attempt. We use a few coverage ops that haven't been updated to handle MSAA yet, and other times we trigger MSAA when we shouldn't, but it sets the basic functionality in place. Bug: skia:11396 Change-Id: I8acfe4283bccf5543d4b774692e39427142b3228 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/395996 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
b0ada77326
commit
710e1c9226
@ -431,3 +431,8 @@ GrDstSampleType GrCaps::getDstSampleTypeForProxy(const GrRenderTargetProxy* rt)
|
||||
}
|
||||
return GrDstSampleType::kAsTextureCopy;
|
||||
}
|
||||
|
||||
bool GrCaps::supportsDynamicMSAA(const GrRenderTargetProxy* rtProxy) const {
|
||||
return this->internalMultisampleCount(rtProxy->backendFormat()) > 1 &&
|
||||
this->onSupportsDynamicMSAA(rtProxy);
|
||||
}
|
||||
|
@ -473,6 +473,8 @@ public:
|
||||
return GrInternalSurfaceFlags::kNone;
|
||||
}
|
||||
|
||||
bool supportsDynamicMSAA(const GrRenderTargetProxy*) const;
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
struct TestFormatColorTypeCombination {
|
||||
GrColorType fColorType;
|
||||
@ -488,6 +490,8 @@ protected:
|
||||
// NOTE: this method will only reduce the caps, never expand them.
|
||||
void finishInitialization(const GrContextOptions& options);
|
||||
|
||||
virtual bool onSupportsDynamicMSAA(const GrRenderTargetProxy*) const { return false; }
|
||||
|
||||
sk_sp<GrShaderCaps> fShaderCaps;
|
||||
|
||||
bool fNPOTTextureTileSupport : 1;
|
||||
|
@ -391,8 +391,9 @@ void GrOpsTask::addOp(GrDrawingManager* drawingMgr, GrOp::Owner op,
|
||||
}
|
||||
|
||||
void GrOpsTask::addDrawOp(GrDrawingManager* drawingMgr, GrOp::Owner op,
|
||||
const GrProcessorSet::Analysis& processorAnalysis,
|
||||
GrAppliedClip&& clip, const DstProxyView& dstProxyView,
|
||||
GrDrawOp::FixedFunctionFlags fixedFunctionFlags,
|
||||
const GrProcessorSet::Analysis& processorAnalysis, GrAppliedClip&& clip,
|
||||
const DstProxyView& dstProxyView,
|
||||
GrTextureResolveManager textureResolveManager, const GrCaps& caps) {
|
||||
auto addDependency = [&](GrSurfaceProxy* p, GrMipmapped mipmapped) {
|
||||
this->addSampledTexture(p);
|
||||
@ -420,6 +421,16 @@ void GrOpsTask::addDrawOp(GrDrawingManager* drawingMgr, GrOp::Owner op,
|
||||
fRenderPassXferBarriers |= GrXferBarrierFlags::kBlend;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
// Ensure we can support dynamic msaa if the caller is trying to trigger it.
|
||||
GrRenderTargetProxy* rtProxy = this->target(0)->asRenderTargetProxy();
|
||||
if (rtProxy->numSamples() == 1 &&
|
||||
(fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA)) {
|
||||
SkASSERT(caps.supportsDynamicMSAA(rtProxy));
|
||||
}
|
||||
#endif
|
||||
fUsesMSAASurface |= (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA);
|
||||
|
||||
this->recordOp(std::move(op), processorAnalysis, clip.doesClip() ? &clip : nullptr,
|
||||
&dstProxyView, caps);
|
||||
}
|
||||
@ -715,6 +726,7 @@ int GrOpsTask::mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks) {
|
||||
fClippedContentBounds.join(opsTask->fClippedContentBounds);
|
||||
fTotalBounds.join(opsTask->fTotalBounds);
|
||||
fRenderPassXferBarriers |= opsTask->fRenderPassXferBarriers;
|
||||
fUsesMSAASurface |= opsTask->fUsesMSAASurface;
|
||||
SkDEBUGCODE(fNumClips += opsTask->fNumClips);
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,9 @@ public:
|
||||
|
||||
void addOp(GrDrawingManager*, GrOp::Owner, GrTextureResolveManager, const GrCaps&);
|
||||
|
||||
void addDrawOp(GrDrawingManager*, GrOp::Owner, const GrProcessorSet::Analysis&,
|
||||
GrAppliedClip&&, const DstProxyView&, GrTextureResolveManager, const GrCaps&);
|
||||
void addDrawOp(GrDrawingManager*, GrOp::Owner, GrDrawOp::FixedFunctionFlags,
|
||||
const GrProcessorSet::Analysis&, GrAppliedClip&&, const DstProxyView&,
|
||||
GrTextureResolveManager, const GrCaps&);
|
||||
|
||||
void discard();
|
||||
|
||||
|
@ -493,11 +493,20 @@ sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int num_stencil_samples(const GrRenderTarget* rt, bool useMSAASurface, const GrCaps& caps) {
|
||||
int numSamples = rt->numSamples();
|
||||
if (numSamples == 1 && useMSAASurface) { // Are we using dynamic msaa?
|
||||
numSamples = caps.internalMultisampleCount(rt->backendFormat());
|
||||
SkASSERT(numSamples > 1); // Caller must ensure dmsaa is supported before trying to use it.
|
||||
}
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSAASurface) {
|
||||
SkASSERT(rt);
|
||||
GrAttachment* stencil = rt->getStencilAttachment(useMSAASurface);
|
||||
if (stencil) {
|
||||
SkASSERT(stencil->numSamples() == rt->numSamples());
|
||||
SkASSERT(stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -515,15 +524,16 @@ bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSA
|
||||
return false;
|
||||
}
|
||||
GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
|
||||
int numStencilSamples = num_stencil_samples(rt, useMSAASurface, *this->caps());
|
||||
GrAttachment::ComputeSharedAttachmentUniqueKey(
|
||||
*this->caps(), stencilFormat, rt->dimensions(),
|
||||
GrAttachment::UsageFlags::kStencilAttachment, rt->numSamples(), GrMipmapped::kNo,
|
||||
GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, GrMipmapped::kNo,
|
||||
isProtected, &sbKey);
|
||||
auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
|
||||
if (!stencil) {
|
||||
// Need to try and create a new stencil
|
||||
stencil = this->gpu()->makeStencilAttachment(rt->backendFormat(), rt->dimensions(),
|
||||
rt->numSamples());
|
||||
numStencilSamples);
|
||||
if (!stencil) {
|
||||
return false;
|
||||
}
|
||||
@ -532,7 +542,8 @@ bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSA
|
||||
rt->attachStencilAttachment(std::move(stencil), useMSAASurface);
|
||||
}
|
||||
stencil = rt->getStencilAttachment(useMSAASurface);
|
||||
SkASSERT(!stencil || stencil->numSamples() == rt->numSamples());
|
||||
SkASSERT(!stencil ||
|
||||
stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
|
||||
return stencil != nullptr;
|
||||
}
|
||||
|
||||
|
@ -299,6 +299,9 @@ GrSurfaceDrawContext::GrSurfaceDrawContext(GrRecordingContext* context,
|
||||
{colorType, kPremul_SkAlphaType, std::move(colorSpace)},
|
||||
flushTimeOpsTask)
|
||||
, fSurfaceProps(surfaceProps)
|
||||
, fCanUseDynamicMSAA(
|
||||
(fSurfaceProps.flags() & kDMSAA_SkSurfacePropsPrivateFlag) &&
|
||||
context->priv().caps()->supportsDynamicMSAA(this->asRenderTargetProxy()))
|
||||
, fGlyphPainter(*this) {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
@ -319,6 +322,12 @@ void GrSurfaceDrawContext::willReplaceOpsTask(GrOpsTask* prevTask, GrOpsTask* ne
|
||||
}
|
||||
|
||||
inline GrAAType GrSurfaceDrawContext::chooseAAType(GrAA aa) {
|
||||
if (fCanUseDynamicMSAA) {
|
||||
// Trigger dmsaa by default if the render target has it. Coverage ops that know how to
|
||||
// handle both single and multisample targets without popping will do so without calling
|
||||
// chooseAAType.
|
||||
return GrAAType::kMSAA;
|
||||
}
|
||||
if (GrAA::kNo == aa) {
|
||||
// On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
|
||||
// that.
|
||||
@ -619,8 +628,17 @@ void GrSurfaceDrawContext::drawFilledQuad(const GrClip* clip,
|
||||
if (opt >= QuadOptimization::kClipApplied) {
|
||||
// These optimizations require caller to add an op themselves
|
||||
const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
|
||||
GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone)
|
||||
: this->chooseAAType(aa);
|
||||
GrAAType aaType;
|
||||
if (ss) {
|
||||
aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
|
||||
} else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
|
||||
// The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
|
||||
// into here with GrAA::kNo, trust that they know what they're doing and that the
|
||||
// rendering will be equal with or without msaa.
|
||||
aaType = GrAAType::kNone;
|
||||
} else {
|
||||
aaType = this->chooseAAType(aa);
|
||||
}
|
||||
this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
|
||||
quad, ss));
|
||||
}
|
||||
@ -743,7 +761,7 @@ void GrSurfaceDrawContext::drawRect(const GrClip* clip,
|
||||
(rect.width() && rect.height())) {
|
||||
// Only use the StrokeRectOp for non-empty rectangles. Empty rectangles will be processed by
|
||||
// GrStyledShape to handle stroke caps and dashing properly.
|
||||
GrAAType aaType = this->chooseAAType(aa);
|
||||
GrAAType aaType = (fCanUseDynamicMSAA) ? GrAAType::kCoverage : this->chooseAAType(aa);
|
||||
GrOp::Owner op = GrStrokeRectOp::Make(
|
||||
fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
|
||||
// op may be null if the stroke is not supported or if using coverage aa and the view matrix
|
||||
@ -1079,7 +1097,7 @@ void GrSurfaceDrawContext::drawRRect(const GrClip* origClip,
|
||||
op = GrFillRRectOp::Make(fContext, std::move(paint), viewMatrix, rrect, rrect.rect(),
|
||||
GrAA(aaType != GrAAType::kNone));
|
||||
}
|
||||
if (!op && GrAAType::kCoverage == aaType) {
|
||||
if (!op && (GrAAType::kCoverage == aaType || fCanUseDynamicMSAA)) {
|
||||
assert_alive(paint);
|
||||
op = GrOvalOpFactory::MakeRRectOp(
|
||||
fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
|
||||
@ -1392,7 +1410,7 @@ void GrSurfaceDrawContext::drawOval(const GrClip* clip,
|
||||
op = GrFillRRectOp::Make(fContext, std::move(paint), viewMatrix, SkRRect::MakeOval(oval),
|
||||
oval, GrAA(aaType != GrAAType::kNone));
|
||||
}
|
||||
if (!op && GrAAType::kCoverage == aaType) {
|
||||
if (!op && (GrAAType::kCoverage == aaType || fCanUseDynamicMSAA)) {
|
||||
assert_alive(paint);
|
||||
op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
|
||||
this->caps()->shaderCaps());
|
||||
@ -1425,7 +1443,7 @@ void GrSurfaceDrawContext::drawArc(const GrClip* clip,
|
||||
AutoCheckFlush acf(this->drawingManager());
|
||||
|
||||
GrAAType aaType = this->chooseAAType(aa);
|
||||
if (GrAAType::kCoverage == aaType) {
|
||||
if (GrAAType::kCoverage == aaType || fCanUseDynamicMSAA) {
|
||||
const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
|
||||
GrOp::Owner op = GrOvalOpFactory::MakeArcOp(fContext,
|
||||
std::move(paint),
|
||||
@ -1938,9 +1956,9 @@ void GrSurfaceDrawContext::addDrawOp(const GrClip* clip,
|
||||
if (willAddFn) {
|
||||
willAddFn(op.get(), opsTask->uniqueID());
|
||||
}
|
||||
opsTask->addDrawOp(this->drawingManager(), std::move(op), analysis, std::move(appliedClip),
|
||||
dstProxyView, GrTextureResolveManager(this->drawingManager()),
|
||||
*this->caps());
|
||||
opsTask->addDrawOp(this->drawingManager(), std::move(op), fixedFunctionFlags, analysis,
|
||||
std::move(appliedClip), dstProxyView,
|
||||
GrTextureResolveManager(this->drawingManager()), *this->caps());
|
||||
}
|
||||
|
||||
bool GrSurfaceDrawContext::setupDstProxyView(const GrOp& op,
|
||||
|
@ -729,7 +729,8 @@ private:
|
||||
|
||||
SkGlyphRunListPainter* glyphPainter() { return &fGlyphPainter; }
|
||||
|
||||
SkSurfaceProps fSurfaceProps;
|
||||
const SkSurfaceProps fSurfaceProps;
|
||||
const bool fCanUseDynamicMSAA;
|
||||
|
||||
bool fNeedsStencil = false;
|
||||
|
||||
|
@ -306,6 +306,7 @@ void GrSurfaceFillContext::addDrawOp(GrOp::Owner owner) {
|
||||
GrXferProcessor::DstProxyView dstProxyView;
|
||||
this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(),
|
||||
std::move(owner),
|
||||
op->fixedFunctionFlags(),
|
||||
analysis,
|
||||
std::move(clip),
|
||||
dstProxyView,
|
||||
|
@ -25,7 +25,8 @@ public:
|
||||
GrProtected::kNo)
|
||||
, fFormat(format)
|
||||
, fRenderbufferID(idDesc.fRenderbufferID) {
|
||||
SkASSERT(supportedUsages == UsageFlags::kStencilAttachment);
|
||||
SkASSERT(supportedUsages == UsageFlags::kStencilAttachment ||
|
||||
supportedUsages == UsageFlags::kColorAttachment);
|
||||
this->registerWithCache(SkBudgeted::kYes);
|
||||
}
|
||||
|
||||
|
@ -511,6 +511,20 @@ private:
|
||||
|
||||
GrDstSampleType onGetDstSampleTypeForProxy(const GrRenderTargetProxy*) const override;
|
||||
|
||||
bool onSupportsDynamicMSAA(const GrRenderTargetProxy*) const override {
|
||||
switch (fMSFBOType) {
|
||||
// The Apple extension doesn't support blitting from single to multisample.
|
||||
case kES_Apple_MSFBOType:
|
||||
case kNone_MSFBOType:
|
||||
return false;
|
||||
case kStandard_MSFBOType:
|
||||
case kES_IMG_MsToTexture_MSFBOType:
|
||||
case kES_EXT_MsToTexture_MSFBOType:
|
||||
return true;
|
||||
}
|
||||
SkUNREACHABLE;
|
||||
}
|
||||
|
||||
GrGLStandard fStandard = kNone_GrGLStandard;
|
||||
|
||||
SkTArray<GrGLFormat, true> fStencilFormats;
|
||||
|
@ -1728,6 +1728,25 @@ sk_sp<GrAttachment> GrGLGpu::makeStencilAttachment(const GrBackendFormat& colorF
|
||||
numStencilSamples, sFmt));
|
||||
}
|
||||
|
||||
sk_sp<GrAttachment> GrGLGpu::makeMSAAAttachment(SkISize dimensions, const GrBackendFormat& format,
|
||||
int numSamples, GrProtected isProtected) {
|
||||
GrGLAttachment::IDDesc desc;
|
||||
GL_CALL(GenRenderbuffers(1, &desc.fRenderbufferID));
|
||||
if (!desc.fRenderbufferID) {
|
||||
return nullptr;
|
||||
}
|
||||
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, desc.fRenderbufferID));
|
||||
GrGLenum glFormat = this->glCaps().getRenderbufferInternalFormat(format.asGLFormat());
|
||||
if (!this->renderbufferStorageMSAA(*fGLContext, numSamples, glFormat, dimensions.width(),
|
||||
dimensions.height())) {
|
||||
GL_CALL(DeleteRenderbuffers(1, &desc.fRenderbufferID));
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<GrAttachment>(new GrGLAttachment(this, desc, dimensions,
|
||||
GrAttachment::UsageFlags::kColorAttachment,
|
||||
numSamples, format.asGLFormat()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<GrGpuBuffer> GrGLGpu::onCreateBuffer(size_t size, GrGpuBufferType intendedType,
|
||||
@ -1943,20 +1962,19 @@ static bool use_tiled_rendering(const GrGLCaps& glCaps,
|
||||
GrStoreOp::kDiscard == stencilLoadStore.fStoreOp;
|
||||
}
|
||||
|
||||
void GrGLGpu::beginCommandBuffer(GrRenderTarget* rt, bool useMultisampleFBO, const SkIRect& bounds,
|
||||
GrSurfaceOrigin origin,
|
||||
void GrGLGpu::beginCommandBuffer(GrGLRenderTarget* rt, bool useMultisampleFBO,
|
||||
const SkIRect& bounds, GrSurfaceOrigin origin,
|
||||
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
|
||||
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore) {
|
||||
SkASSERT(!fIsExecutingCommandBuffer_DebugOnly);
|
||||
|
||||
this->handleDirtyContext();
|
||||
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(rt);
|
||||
this->flushRenderTarget(glRT, useMultisampleFBO);
|
||||
this->flushRenderTarget(rt, useMultisampleFBO);
|
||||
SkDEBUGCODE(fIsExecutingCommandBuffer_DebugOnly = true);
|
||||
|
||||
if (use_tiled_rendering(this->glCaps(), stencilLoadStore)) {
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(origin, glRT->height(), bounds);
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(origin, rt->height(), bounds);
|
||||
GrGLbitfield preserveMask = (GrLoadOp::kLoad == colorLoadStore.fLoadOp)
|
||||
? GR_GL_COLOR_BUFFER_BIT0 : GR_GL_NONE;
|
||||
SkASSERT(GrLoadOp::kLoad != stencilLoadStore.fLoadOp); // Handled by use_tiled_rendering().
|
||||
@ -1984,31 +2002,30 @@ void GrGLGpu::beginCommandBuffer(GrRenderTarget* rt, bool useMultisampleFBO, con
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLGpu::endCommandBuffer(GrRenderTarget* rt, bool useMultisampleFBO,
|
||||
void GrGLGpu::endCommandBuffer(GrGLRenderTarget* rt, bool useMultisampleFBO,
|
||||
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
|
||||
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore) {
|
||||
SkASSERT(fIsExecutingCommandBuffer_DebugOnly);
|
||||
|
||||
this->handleDirtyContext();
|
||||
|
||||
if (rt->uniqueID() != fHWBoundRenderTargetUniqueID) {
|
||||
if (rt->uniqueID() != fHWBoundRenderTargetUniqueID ||
|
||||
useMultisampleFBO != fHWBoundFramebufferIsMSAA) {
|
||||
// The framebuffer binding changed in the middle of a command buffer. We should have already
|
||||
// printed a warning during onFBOChanged.
|
||||
return;
|
||||
}
|
||||
|
||||
if (GrGLCaps::kNone_InvalidateFBType != this->glCaps().invalidateFBType()) {
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(rt);
|
||||
|
||||
SkSTArray<2, GrGLenum> discardAttachments;
|
||||
if (GrStoreOp::kDiscard == colorLoadStore.fStoreOp) {
|
||||
GrGLuint renderFBOID = (useMultisampleFBO) ? glRT->multisampleFBOID()
|
||||
: glRT->singleSampleFBOID();
|
||||
GrGLuint renderFBOID = (useMultisampleFBO) ? rt->multisampleFBOID()
|
||||
: rt->singleSampleFBOID();
|
||||
discardAttachments.push_back((!renderFBOID) ? GR_GL_COLOR : GR_GL_COLOR_ATTACHMENT0);
|
||||
}
|
||||
if (GrStoreOp::kDiscard == stencilLoadStore.fStoreOp) {
|
||||
GrGLuint renderFBOID = (useMultisampleFBO) ? glRT->multisampleFBOID()
|
||||
: glRT->singleSampleFBOID();
|
||||
GrGLuint renderFBOID = (useMultisampleFBO) ? rt->multisampleFBOID()
|
||||
: rt->singleSampleFBOID();
|
||||
discardAttachments.push_back((!renderFBOID) ? GR_GL_STENCIL : GR_GL_STENCIL_ATTACHMENT);
|
||||
|
||||
}
|
||||
@ -2173,7 +2190,14 @@ GrOpsRenderPass* GrGLGpu::onGetOpsRenderPass(
|
||||
if (!fCachedOpsRenderPass) {
|
||||
fCachedOpsRenderPass = std::make_unique<GrGLOpsRenderPass>(this);
|
||||
}
|
||||
|
||||
if (useMultisampleFBO && rt->numSamples() == 1) {
|
||||
// We will be using dynamic msaa. Ensure there is an attachment.
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(rt);
|
||||
if (!glRT->ensureDynamicMSAAAttachment()) {
|
||||
SkDebugf("WARNING: Failed to make dmsaa attachment. Render pass will be dropped.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
fCachedOpsRenderPass->set(rt, useMultisampleFBO, bounds, origin, colorInfo, stencilInfo);
|
||||
return fCachedOpsRenderPass.get();
|
||||
}
|
||||
@ -2284,19 +2308,34 @@ GrGLenum GrGLGpu::prepareToDraw(GrPrimitiveType primitiveType) {
|
||||
}
|
||||
|
||||
void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
|
||||
// Some extensions automatically resolves the texture when it is read.
|
||||
SkASSERT(this->glCaps().usesMSAARenderBuffers());
|
||||
this->resolveRenderFBOs(static_cast<GrGLRenderTarget*>(target), resolveRect,
|
||||
ResolveDirection::kMSAAToSingle);
|
||||
}
|
||||
|
||||
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
|
||||
SkASSERT(rt->requiresManualMSAAResolve());
|
||||
SkASSERT(rt->singleSampleFBOID() != 0 && rt->multisampleFBOID() != 0);
|
||||
this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->multisampleFBOID());
|
||||
this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->singleSampleFBOID());
|
||||
void GrGLGpu::resolveRenderFBOs(GrGLRenderTarget* rt, const SkIRect& resolveRect,
|
||||
ResolveDirection resolveDirection,
|
||||
bool invalidateReadBufferAfterBlit) {
|
||||
this->handleDirtyContext();
|
||||
|
||||
// If the multisample FBO is nonzero, it means we always have something to resolve (even if the
|
||||
// single sample buffer is FBO 0). If it's zero, then there's nothing to resolve.
|
||||
SkASSERT(rt->multisampleFBOID() != 0);
|
||||
|
||||
if (resolveDirection == ResolveDirection::kMSAAToSingle) {
|
||||
this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->multisampleFBOID());
|
||||
this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->singleSampleFBOID());
|
||||
} else {
|
||||
SkASSERT(resolveDirection == ResolveDirection::kSingleToMSAA);
|
||||
this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->singleSampleFBOID());
|
||||
this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->multisampleFBOID());
|
||||
}
|
||||
|
||||
// make sure we go through flushRenderTarget() since we've modified
|
||||
// the bound DRAW FBO ID.
|
||||
fHWBoundRenderTargetUniqueID.makeInvalid();
|
||||
if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) {
|
||||
// The Apple extension doesn't support blitting from single to multisample.
|
||||
SkASSERT(resolveDirection != ResolveDirection::kSingleToMSAA);
|
||||
// Apple's extension uses the scissor as the blit bounds.
|
||||
// Passing in kTopLeft_GrSurfaceOrigin will make sure no transformation of the rect
|
||||
// happens inside flushScissor since resolveRect is already in native device coordinates.
|
||||
@ -2311,8 +2350,8 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resol
|
||||
this->glCaps().blitFramebufferSupportFlags()) {
|
||||
l = 0;
|
||||
b = 0;
|
||||
r = target->width();
|
||||
t = target->height();
|
||||
r = rt->width();
|
||||
t = rt->height();
|
||||
} else {
|
||||
l = resolveRect.x();
|
||||
b = resolveRect.y();
|
||||
@ -2325,6 +2364,20 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resol
|
||||
this->disableWindowRectangles();
|
||||
GL_CALL(BlitFramebuffer(l, b, r, t, l, b, r, t, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
|
||||
}
|
||||
|
||||
if (this->glCaps().invalidateFBType() != GrGLCaps::kNone_InvalidateFBType &&
|
||||
invalidateReadBufferAfterBlit) {
|
||||
// Invalidate the read FBO attachment after the blit, in hopes that this allows the driver
|
||||
// to perform tiling optimizations.
|
||||
GrGLenum colorDiscardAttachment = (rt->multisampleFBOID() == 0) ? GR_GL_COLOR
|
||||
: GR_GL_COLOR_ATTACHMENT0;
|
||||
if (this->glCaps().invalidateFBType() == GrGLCaps::kInvalidate_InvalidateFBType) {
|
||||
GL_CALL(InvalidateFramebuffer(GR_GL_READ_FRAMEBUFFER, 1, &colorDiscardAttachment));
|
||||
} else {
|
||||
SkASSERT(this->glCaps().invalidateFBType() == GrGLCaps::kDiscard_InvalidateFBType);
|
||||
GL_CALL(DiscardFramebuffer(GR_GL_READ_FRAMEBUFFER, 1, &colorDiscardAttachment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -2414,7 +2467,8 @@ void GrGLGpu::disableStencil() {
|
||||
void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) {
|
||||
// rt is only optional if useHWAA is false.
|
||||
SkASSERT(rt || !useHWAA);
|
||||
SkASSERT(!useHWAA || rt->numSamples() > 1);
|
||||
SkASSERT(!useHWAA || rt->numSamples() > 1 ||
|
||||
static_cast<GrGLRenderTarget*>(rt)->multisampleFBOID());
|
||||
|
||||
if (this->caps()->multisampleDisableSupport()) {
|
||||
if (useHWAA) {
|
||||
|
@ -103,6 +103,14 @@ public:
|
||||
// Applies any necessary workarounds and returns the GL primitive type to use in draw calls.
|
||||
GrGLenum prepareToDraw(GrPrimitiveType primitiveType);
|
||||
|
||||
enum class ResolveDirection : bool {
|
||||
kSingleToMSAA,
|
||||
kMSAAToSingle
|
||||
};
|
||||
|
||||
void resolveRenderFBOs(GrGLRenderTarget*, const SkIRect& resolveRect, ResolveDirection,
|
||||
bool invalidateReadBufferAfterBlit = false);
|
||||
|
||||
// The GrGLOpsRenderPass 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 GrGLOpsRenderPass.
|
||||
@ -115,12 +123,12 @@ public:
|
||||
void clearStencilClip(const GrScissorState&, bool insideStencilMask,
|
||||
GrRenderTarget*, bool useMultisampleFBO, GrSurfaceOrigin);
|
||||
|
||||
void beginCommandBuffer(GrRenderTarget*, bool useMultisampleFBO,
|
||||
void beginCommandBuffer(GrGLRenderTarget*, bool useMultisampleFBO,
|
||||
const SkIRect& bounds, GrSurfaceOrigin,
|
||||
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
|
||||
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore);
|
||||
|
||||
void endCommandBuffer(GrRenderTarget*, bool useMultisampleFBO,
|
||||
void endCommandBuffer(GrGLRenderTarget*, bool useMultisampleFBO,
|
||||
const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore,
|
||||
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore);
|
||||
|
||||
@ -134,9 +142,7 @@ public:
|
||||
sk_sp<GrAttachment> makeMSAAAttachment(SkISize dimensions,
|
||||
const GrBackendFormat& format,
|
||||
int numSamples,
|
||||
GrProtected isProtected) override {
|
||||
return nullptr;
|
||||
}
|
||||
GrProtected isProtected) override;
|
||||
|
||||
void deleteBackendTexture(const GrBackendTexture&) override;
|
||||
|
||||
|
@ -32,13 +32,34 @@ void GrGLOpsRenderPass::set(GrRenderTarget* rt, bool useMSAASurface, const SkIRe
|
||||
}
|
||||
|
||||
void GrGLOpsRenderPass::onBegin() {
|
||||
fGpu->beginCommandBuffer(fRenderTarget, fUseMultisampleFBO, fContentBounds, fOrigin,
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(fRenderTarget);
|
||||
if (fUseMultisampleFBO && fColorLoadAndStoreInfo.fLoadOp == GrLoadOp::kLoad &&
|
||||
glRT->hasDynamicMSAAAttachment()) {
|
||||
// Blit the single sample fbo into the dmsaa attachment.
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
|
||||
fContentBounds);
|
||||
fGpu->resolveRenderFBOs(glRT, nativeBounds.asSkIRect(),
|
||||
GrGLGpu::ResolveDirection::kSingleToMSAA);
|
||||
}
|
||||
|
||||
fGpu->beginCommandBuffer(glRT, fUseMultisampleFBO, fContentBounds, fOrigin,
|
||||
fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo);
|
||||
}
|
||||
|
||||
void GrGLOpsRenderPass::onEnd() {
|
||||
fGpu->endCommandBuffer(fRenderTarget, fUseMultisampleFBO, fColorLoadAndStoreInfo,
|
||||
auto glRT = static_cast<GrGLRenderTarget*>(fRenderTarget);
|
||||
fGpu->endCommandBuffer(glRT, fUseMultisampleFBO, fColorLoadAndStoreInfo,
|
||||
fStencilLoadAndStoreInfo);
|
||||
|
||||
if (fUseMultisampleFBO && fColorLoadAndStoreInfo.fStoreOp == GrStoreOp::kStore &&
|
||||
glRT->hasDynamicMSAAAttachment()) {
|
||||
// Blit the msaa attachment into the single sample fbo.
|
||||
auto nativeBounds = GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(),
|
||||
fContentBounds);
|
||||
fGpu->resolveRenderFBOs(glRT, nativeBounds.asSkIRect(),
|
||||
GrGLGpu::ResolveDirection::kMSAAToSingle,
|
||||
true /*invalidateReadBufferAfterBlit*/);
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
|
||||
|
@ -125,12 +125,17 @@ size_t GrGLRenderTarget::onGpuMemorySize() const {
|
||||
}
|
||||
|
||||
bool GrGLRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool useMultisampleFBO) {
|
||||
SkASSERT(useMultisampleFBO == (this->numSamples() > 1));
|
||||
GrGLGpu* gpu = this->getGLGpu();
|
||||
const GrGLInterface* interface = gpu->glInterface();
|
||||
GrGLuint stencilFBOID = (useMultisampleFBO) ? fMultisampleFBOID : fSingleSampleFBOID;
|
||||
|
||||
gpu->invalidateBoundRenderTarget();
|
||||
if (this->numSamples() == 1 && useMultisampleFBO) {
|
||||
// We will be rendering to the dynamic msaa fbo. Make sure to initialize it first.
|
||||
if (!this->ensureDynamicMSAAAttachment()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GrGLuint stencilFBOID = (useMultisampleFBO) ? fMultisampleFBOID : fSingleSampleFBOID;
|
||||
gpu->bindFramebuffer(GR_GL_FRAMEBUFFER, stencilFBOID);
|
||||
|
||||
if (nullptr == stencil) {
|
||||
@ -170,6 +175,49 @@ bool GrGLRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool use
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrGLRenderTarget::ensureDynamicMSAAAttachment() {
|
||||
SkASSERT(this->numSamples() == 1);
|
||||
if (fMultisampleFBOID) {
|
||||
return true;
|
||||
}
|
||||
SkASSERT(!fDynamicMSAAAttachment);
|
||||
|
||||
GrResourceProvider* resourceProvider = this->getContext()->priv().resourceProvider();
|
||||
const GrCaps& caps = *this->getGpu()->caps();
|
||||
|
||||
int internalSampleCount = caps.internalMultisampleCount(this->backendFormat());
|
||||
if (internalSampleCount <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GL_CALL(GenFramebuffers(1, &fMultisampleFBOID));
|
||||
if (!fMultisampleFBOID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->getGLGpu()->bindFramebuffer(GR_GL_FRAMEBUFFER, fMultisampleFBOID);
|
||||
|
||||
if (resourceProvider->caps()->msaaResolvesAutomatically()) {
|
||||
if (GrGLTexture* glTex = static_cast<GrGLTexture*>(this->asTexture())) {
|
||||
GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
|
||||
glTex->target(), glTex->textureID(),
|
||||
0 /*mipMapLevel*/, internalSampleCount));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fDynamicMSAAAttachment.reset(static_cast<GrGLAttachment*>(resourceProvider->makeMSAAAttachment(
|
||||
this->dimensions(), this->backendFormat(), internalSampleCount,
|
||||
GrProtected(this->isProtected())).release()));
|
||||
if (!fDynamicMSAAAttachment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_RENDERBUFFER,
|
||||
fDynamicMSAAAttachment->renderbufferID()));
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrGLRenderTarget::onRelease() {
|
||||
if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) {
|
||||
GrGLGpu* gpu = this->getGLGpu();
|
||||
@ -204,7 +252,6 @@ GrGLGpu* GrGLRenderTarget::getGLGpu() const {
|
||||
}
|
||||
|
||||
bool GrGLRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const {
|
||||
SkASSERT(useMultisampleFBO == (this->numSamples() > 1));
|
||||
if (this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers()) {
|
||||
return false;
|
||||
}
|
||||
@ -212,7 +259,9 @@ bool GrGLRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const
|
||||
// Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
|
||||
// allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
|
||||
// Skia created it.
|
||||
return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned;
|
||||
return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned ||
|
||||
// The dmsaa attachment is always owned and always supports adding stencil.
|
||||
(this->numSamples() == 1 && useMultisampleFBO);
|
||||
}
|
||||
|
||||
void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
|
||||
|
@ -56,6 +56,9 @@ public:
|
||||
|
||||
GrGLFormat format() const { return fRTFormat; }
|
||||
|
||||
bool hasDynamicMSAAAttachment() const { return SkToBool(fDynamicMSAAAttachment); }
|
||||
bool ensureDynamicMSAAAttachment();
|
||||
|
||||
protected:
|
||||
// Constructor for subclasses.
|
||||
GrGLRenderTarget(GrGLGpu*,
|
||||
@ -83,6 +86,8 @@ private:
|
||||
|
||||
size_t onGpuMemorySize() const override;
|
||||
|
||||
sk_sp<GrGLAttachment> fDynamicMSAAAttachment;
|
||||
|
||||
GrGLuint fMultisampleFBOID;
|
||||
GrGLuint fSingleSampleFBOID;
|
||||
GrGLuint fMSColorRenderbufferID;
|
||||
|
Loading…
Reference in New Issue
Block a user