Fix texture barriers on DMSAA
Bug: skia:11396 Change-Id: Iad74958c05ed086fe85656b9dc5418d5ab4589e7 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/419838 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Chris Dalton <csmartdalton@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
d0f4d0d5d4
commit
1a3f4ab490
@ -292,6 +292,17 @@ struct SK_API GrContextOptions {
|
||||
*/
|
||||
bool fSuppressDualSourceBlending = false;
|
||||
|
||||
/**
|
||||
* Prevents the use of non-coefficient-based blend equations, for testing dst reads, barriers,
|
||||
* and in-shader blending.
|
||||
*/
|
||||
bool fSuppressAdvancedBlendEquations = false;
|
||||
|
||||
/**
|
||||
* Prevents the use of framebuffer fetches, for testing dst reads and texture barriers.
|
||||
*/
|
||||
bool fSuppressFramebufferFetch = false;
|
||||
|
||||
/**
|
||||
* If true, the caps will never support geometry shaders.
|
||||
*/
|
||||
|
@ -133,6 +133,9 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
|
||||
|
||||
fMaxTextureSize = std::min(fMaxTextureSize, options.fMaxTextureSizeOverride);
|
||||
#if GR_TEST_UTILS
|
||||
if (options.fSuppressAdvancedBlendEquations) {
|
||||
fBlendEquationSupport = kBasic_BlendEquationSupport;
|
||||
}
|
||||
if (options.fClearAllTextures) {
|
||||
fShouldInitializeTextures = true;
|
||||
}
|
||||
@ -140,6 +143,9 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
|
||||
fWritePixelsRowBytesSupport = false;
|
||||
fTransferPixelsToRowBytesSupport = false;
|
||||
}
|
||||
if (options.fAlwaysPreferHardwareTessellation) {
|
||||
fMinPathVerbsForHwTessellation = fMinStrokeVerbsForHwTessellation = 0;
|
||||
}
|
||||
#endif
|
||||
if (options.fSuppressMipmapSupport) {
|
||||
fMipmapSupport = false;
|
||||
@ -153,12 +159,6 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
|
||||
|
||||
fInternalMultisampleCount = options.fInternalMultisampleCount;
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
if (options.fAlwaysPreferHardwareTessellation) {
|
||||
fMinPathVerbsForHwTessellation = fMinStrokeVerbsForHwTessellation = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
fAvoidStencilBuffers = options.fAvoidStencilBuffers;
|
||||
|
||||
fDriverBugWorkarounds.applyOverrides(options.fDriverBugWorkarounds);
|
||||
@ -438,9 +438,10 @@ bool GrCaps::isFormatCompressed(const GrBackendFormat& format) const {
|
||||
return GrBackendFormatToCompressionType(format) != SkImage::CompressionType::kNone;
|
||||
}
|
||||
|
||||
GrDstSampleFlags GrCaps::getDstSampleFlagsForProxy(const GrRenderTargetProxy* rt) const {
|
||||
GrDstSampleFlags GrCaps::getDstSampleFlagsForProxy(const GrRenderTargetProxy* rt,
|
||||
bool drawUsesMSAA) const {
|
||||
SkASSERT(rt);
|
||||
if (this->textureBarrierSupport() && !rt->requiresManualMSAAResolve()) {
|
||||
if (this->textureBarrierSupport() && (!drawUsesMSAA || this->msaaResolvesAutomatically())) {
|
||||
return this->onGetDstSampleFlagsForProxy(rt);
|
||||
}
|
||||
return GrDstSampleFlags::kNone;
|
||||
|
@ -400,7 +400,7 @@ public:
|
||||
bool alwaysDrawQuadsIndexed() const { return fAlwaysDrawQuadsIndexed; }
|
||||
|
||||
// Returns how to sample the dst values for the passed in GrRenderTargetProxy.
|
||||
GrDstSampleFlags getDstSampleFlagsForProxy(const GrRenderTargetProxy*) const;
|
||||
GrDstSampleFlags getDstSampleFlagsForProxy(const GrRenderTargetProxy*, bool drawUsesMSAA) const;
|
||||
|
||||
/**
|
||||
* This is used to try to ensure a successful copy a dst in order to perform shader-based
|
||||
|
@ -373,14 +373,14 @@ void GrDrawingManager::sortTasks() {
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
// This block checks for any unnecessary splits in the opsTasks. If two sequential opsTasks
|
||||
// share the same backing GrSurfaceProxy it means the opsTask was artificially split.
|
||||
// could have merged it means the opsTask was artificially split.
|
||||
if (!fDAG.empty()) {
|
||||
GrOpsTask* prevOpsTask = fDAG[0]->asOpsTask();
|
||||
for (int i = 1; i < fDAG.count(); ++i) {
|
||||
GrOpsTask* curOpsTask = fDAG[i]->asOpsTask();
|
||||
|
||||
if (prevOpsTask && curOpsTask) {
|
||||
SkASSERT(prevOpsTask->target(0) != curOpsTask->target(0));
|
||||
SkASSERT(!prevOpsTask->canMerge(curOpsTask));
|
||||
}
|
||||
|
||||
prevOpsTask = curOpsTask;
|
||||
|
@ -442,7 +442,8 @@ void GrOpsTask::onPrePrepare(GrRecordingContext* context) {
|
||||
// can end up with GrOpsTasks that only have a discard load op and no ops. For vulkan validation
|
||||
// we need to keep that discard and not drop it. Once we have reduce op list splitting enabled
|
||||
// we shouldn't end up with GrOpsTasks with only discard.
|
||||
if (this->isNoOp() || (fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
if (this->isColorNoOp() ||
|
||||
(fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
return;
|
||||
}
|
||||
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
|
||||
@ -467,7 +468,8 @@ void GrOpsTask::onPrepare(GrOpFlushState* flushState) {
|
||||
// can end up with GrOpsTasks that only have a discard load op and no ops. For vulkan validation
|
||||
// we need to keep that discard and not drop it. Once we have reduce op list splitting enabled
|
||||
// we shouldn't end up with GrOpsTasks with only discard.
|
||||
if (this->isNoOp() || (fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
if (this->isColorNoOp() ||
|
||||
(fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
return;
|
||||
}
|
||||
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
|
||||
@ -548,7 +550,8 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) {
|
||||
// can end up with GrOpsTasks that only have a discard load op and no ops. For vulkan validation
|
||||
// we need to keep that discard and not drop it. Once we have reduce op list splitting enabled
|
||||
// we shouldn't end up with GrOpsTasks with only discard.
|
||||
if (this->isNoOp() || (fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
if (this->isColorNoOp() ||
|
||||
(fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -684,12 +687,17 @@ void GrOpsTask::reset() {
|
||||
fRenderPassXferBarriers = GrXferBarrierFlags::kNone;
|
||||
}
|
||||
|
||||
bool GrOpsTask::canMerge(const GrOpsTask* opsTask) const {
|
||||
return this->target(0) == opsTask->target(0) &&
|
||||
fArenas == opsTask->fArenas &&
|
||||
!opsTask->fCannotMergeBackward;
|
||||
}
|
||||
|
||||
int GrOpsTask::mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks) {
|
||||
int mergedCount = 0;
|
||||
for (const sk_sp<GrRenderTask>& task : tasks) {
|
||||
auto opsTask = task->asOpsTask();
|
||||
if (!opsTask || opsTask->target(0) != this->target(0)
|
||||
|| this->fArenas != opsTask->fArenas) {
|
||||
if (!opsTask || !this->canMerge(opsTask)) {
|
||||
break;
|
||||
}
|
||||
SkASSERT(fTargetSwizzle == opsTask->fTargetSwizzle);
|
||||
@ -871,7 +879,7 @@ void GrOpsTask::onMakeSkippable() {
|
||||
this->deleteOps();
|
||||
fDeferredProxies.reset();
|
||||
fColorLoadOp = GrLoadOp::kLoad;
|
||||
SkASSERT(this->isNoOp());
|
||||
SkASSERT(this->isColorNoOp());
|
||||
}
|
||||
|
||||
bool GrOpsTask::onIsUsed(GrSurfaceProxy* proxyToCheck) const {
|
||||
@ -898,7 +906,7 @@ bool GrOpsTask::onIsUsed(GrSurfaceProxy* proxyToCheck) const {
|
||||
|
||||
void GrOpsTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
|
||||
SkASSERT(this->isClosed());
|
||||
if (this->isNoOp()) {
|
||||
if (this->isColorNoOp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1043,7 +1051,7 @@ void GrOpsTask::forwardCombine(const GrCaps& caps) {
|
||||
GrRenderTask::ExpectedOutcome GrOpsTask::onMakeClosed(const GrCaps& caps,
|
||||
SkIRect* targetUpdateBounds) {
|
||||
this->forwardCombine(caps);
|
||||
if (!this->isNoOp()) {
|
||||
if (!this->isColorNoOp()) {
|
||||
GrSurfaceProxy* proxy = this->target(0);
|
||||
// Use the entire backing store bounds since the GPU doesn't clip automatically to the
|
||||
// logical dimensions.
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
|
||||
bool isEmpty() const { return fOpChains.empty(); }
|
||||
bool usesMSAASurface() const { return fUsesMSAASurface; }
|
||||
GrXferBarrierFlags renderPassXferBarriers() const { return fRenderPassXferBarriers; }
|
||||
|
||||
/**
|
||||
* Empties the draw buffer of any queued up draws.
|
||||
@ -87,6 +88,9 @@ public:
|
||||
// Must only be called if native color buffer clearing is enabled.
|
||||
void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
|
||||
|
||||
// Returns whether the given opsTask can be appended at the end of this one.
|
||||
bool canMerge(const GrOpsTask*) const;
|
||||
|
||||
// Merge as many opsTasks as possible from the head of 'tasks'. They should all be
|
||||
// renderPass compatible. Return the number of tasks merged into 'this'.
|
||||
int mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks);
|
||||
@ -107,12 +111,9 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool isNoOp() const {
|
||||
bool isColorNoOp() const {
|
||||
// TODO: GrLoadOp::kDiscard (i.e., storing a discard) should also be grounds for skipping
|
||||
// execution. We currently don't because of Vulkan. See http://skbug.com/9373.
|
||||
//
|
||||
// TODO: We should also consider stencil load/store here. We get away with it for now
|
||||
// because we never discard stencil buffers.
|
||||
return fOpChains.empty() && GrLoadOp::kLoad == fColorLoadOp;
|
||||
}
|
||||
|
||||
@ -142,6 +143,11 @@ private:
|
||||
// get preserved across its split tasks.
|
||||
void setMustPreserveStencil() { fMustPreserveStencil = true; }
|
||||
|
||||
// Prevents this opsTask from merging backward. This is used by DMSAA when a non-multisampled
|
||||
// opsTask cannot be promoted to MSAA, or when we split a multisampled opsTask in order to
|
||||
// resolve its texture.
|
||||
void setCannotMergeBackward() { fCannotMergeBackward = true; }
|
||||
|
||||
class OpChain {
|
||||
public:
|
||||
OpChain(GrOp::Owner, GrProcessorSet::Analysis, GrAppliedClip*, const GrDstProxyView*);
|
||||
@ -254,6 +260,7 @@ private:
|
||||
std::array<float, 4> fLoadClearColor = {0, 0, 0, 0};
|
||||
StencilContent fInitialStencilContent = StencilContent::kDontCare;
|
||||
bool fMustPreserveStencil = false;
|
||||
bool fCannotMergeBackward = false;
|
||||
|
||||
uint32_t fLastClipStackGenID = SK_InvalidUniqueID;
|
||||
SkIRect fLastDevClipBounds;
|
||||
|
@ -196,6 +196,9 @@ void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) {
|
||||
if (options.fSuppressDualSourceBlending) {
|
||||
fDualSourceBlendingSupport = false;
|
||||
}
|
||||
if (options.fSuppressFramebufferFetch) {
|
||||
fFBFetchSupport = false;
|
||||
}
|
||||
if (options.fSuppressGeometryShaders) {
|
||||
fGeometryShaderSupport = false;
|
||||
}
|
||||
|
@ -1931,11 +1931,43 @@ void GrSurfaceDrawContext::addDrawOp(const GrClip* clip,
|
||||
// Must be called before setDstProxyView so that it sees the final bounds of the op.
|
||||
op->setClippedBounds(bounds);
|
||||
|
||||
// Determine if the Op will trigger the use of a separate DMSAA attachment that requires manual
|
||||
// resolves.
|
||||
// TODO: Currently usesAttachmentIfDMSAA checks if this is a textureProxy or not. This check is
|
||||
// really only for GL which uses a normal texture sampling when using barriers. For Vulkan it
|
||||
// is possible to use the msaa buffer as an input attachment even if this is not a texture.
|
||||
// However, support for that is not fully implemented yet in Vulkan. Once it is, this check
|
||||
// should change to a virtual caps check that returns whether we need to break up an OpsTask
|
||||
// if it has barriers and we are about to promote to MSAA.
|
||||
bool usesAttachmentIfDMSAA =
|
||||
fCanUseDynamicMSAA &&
|
||||
(!this->caps()->msaaResolvesAutomatically() || !this->asTextureProxy());
|
||||
bool opRequiresDMSAAAttachment = usesAttachmentIfDMSAA && usesMSAA;
|
||||
bool opTriggersDMSAAAttachment =
|
||||
opRequiresDMSAAAttachment && !this->getOpsTask()->usesMSAASurface();
|
||||
if (opTriggersDMSAAAttachment) {
|
||||
// This will be the op that actually triggers use of a DMSAA attachment. Texture barriers
|
||||
// can't be moved to a DMSAA attachment, so if there already are any on the current opsTask
|
||||
// then we need to split.
|
||||
if (this->getOpsTask()->renderPassXferBarriers() & GrXferBarrierFlags::kTexture) {
|
||||
SkASSERT(!this->getOpsTask()->isColorNoOp());
|
||||
this->replaceOpsTask()->setCannotMergeBackward();
|
||||
}
|
||||
}
|
||||
|
||||
GrDstProxyView dstProxyView;
|
||||
if (analysis.requiresDstTexture()) {
|
||||
if (!this->setupDstProxyView(*op, &dstProxyView)) {
|
||||
if (!this->setupDstProxyView(drawOp->bounds(), usesMSAA, &dstProxyView)) {
|
||||
return;
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
if (fCanUseDynamicMSAA && usesMSAA && !this->caps()->msaaResolvesAutomatically()) {
|
||||
// Since we aren't literally writing to the render target texture while using a DMSAA
|
||||
// attachment, we need to resolve that texture before sampling it. Ensure the current
|
||||
// opsTask got closed off in order to initiate an implicit resolve.
|
||||
SkASSERT(this->getOpsTask()->isEmpty());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
auto opsTask = this->getOpsTask();
|
||||
@ -1963,7 +1995,9 @@ void GrSurfaceDrawContext::addDrawOp(const GrClip* clip,
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GrSurfaceDrawContext::setupDstProxyView(const GrOp& op, GrDstProxyView* dstProxyView) {
|
||||
bool GrSurfaceDrawContext::setupDstProxyView(const SkRect& opBounds,
|
||||
bool opRequiresMSAA,
|
||||
GrDstProxyView* dstProxyView) {
|
||||
// If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
|
||||
// don't actually have a VkImage to make a copy of. Additionally we don't have the power to
|
||||
// start and stop the render pass in order to make the copy.
|
||||
@ -1971,16 +2005,56 @@ bool GrSurfaceDrawContext::setupDstProxyView(const GrOp& op, GrDstProxyView* dst
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dstSampleFlags = this->caps()->getDstSampleFlagsForProxy(this->asRenderTargetProxy());
|
||||
// First get the dstSampleFlags as if we will put the draw into the current GrOpsTask
|
||||
auto dstSampleFlags = this->caps()->getDstSampleFlagsForProxy(
|
||||
this->asRenderTargetProxy(), this->getOpsTask()->usesMSAASurface() || opRequiresMSAA);
|
||||
|
||||
// If we don't have barriers for this draw then we will definitely be breaking up the GrOpsTask.
|
||||
// However, if using dynamic MSAA, the new GrOpsTask will not have MSAA already enabled on it
|
||||
// and that may allow us to use texture barriers. So we check if we can use barriers on the new
|
||||
// ops task and then break it up if so.
|
||||
if (!(dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) &&
|
||||
fCanUseDynamicMSAA && this->getOpsTask()->usesMSAASurface() && !opRequiresMSAA) {
|
||||
auto newFlags =
|
||||
this->caps()->getDstSampleFlagsForProxy(this->asRenderTargetProxy(),
|
||||
false/*=opRequiresMSAA*/);
|
||||
if (newFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
|
||||
// We can't have an empty ops task if we are in DMSAA and the ops task already returns
|
||||
// true for usesMSAASurface.
|
||||
SkASSERT(!this->getOpsTask()->isColorNoOp());
|
||||
this->replaceOpsTask()->setCannotMergeBackward();
|
||||
dstSampleFlags = newFlags;
|
||||
}
|
||||
}
|
||||
|
||||
if (dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
|
||||
// If we require a barrier to sample the dst it means we are sampling the RT itself either
|
||||
// as a texture or input attachment.
|
||||
// If we require a barrier to sample the dst it means we are sampling the RT itself
|
||||
// either as a texture or input attachment. In this case we don't need to break up the
|
||||
// GrOpsTask.
|
||||
dstProxyView->setProxyView(this->readSurfaceView());
|
||||
dstProxyView->setOffset(0, 0);
|
||||
dstProxyView->setDstSampleFlags(dstSampleFlags);
|
||||
return true;
|
||||
}
|
||||
SkASSERT(dstSampleFlags == GrDstSampleFlags::kNone);
|
||||
|
||||
// We are using a different surface from the main color attachment to sample the dst from. If we
|
||||
// are in DMSAA we can just use the single sampled RT texture itself. Otherwise, we must do a
|
||||
// copy.
|
||||
// We do have to check if we ended up here becasue we don't have texture barriers but do have
|
||||
// msaaResolvesAutomatically (i.e. render-to-msaa-texture). In that case there will be no op or
|
||||
// barrier between draws to flush the render target before being used as a texture in the next
|
||||
// draw. So in that case we just fall through to doing a copy.
|
||||
if (fCanUseDynamicMSAA && opRequiresMSAA && this->asTextureProxy() &&
|
||||
!this->caps()->msaaResolvesAutomatically()) {
|
||||
this->replaceOpsTaskIfModifiesColor()->setCannotMergeBackward();
|
||||
dstProxyView->setProxyView(this->readSurfaceView());
|
||||
dstProxyView->setOffset(0, 0);
|
||||
dstProxyView->setDstSampleFlags(dstSampleFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we fallback to doing a copy.
|
||||
|
||||
GrColorType colorType = this->colorInfo().colorType();
|
||||
// MSAA consideration: When there is support for reading MSAA samples in the shader we could
|
||||
@ -1993,7 +2067,7 @@ bool GrSurfaceDrawContext::setupDstProxyView(const GrOp& op, GrDstProxyView* dst
|
||||
// If we don't need the whole source, restrict to the op's bounds. We add an extra pixel
|
||||
// of padding to account for AA bloat and the unpredictable rounding of coords near pixel
|
||||
// centers during rasterization.
|
||||
SkIRect conservativeDrawBounds = op.bounds().roundOut();
|
||||
SkIRect conservativeDrawBounds = opBounds.roundOut();
|
||||
conservativeDrawBounds.outset(1, 1);
|
||||
SkAssertResult(copyRect.intersect(conservativeDrawBounds));
|
||||
}
|
||||
@ -2022,3 +2096,11 @@ bool GrSurfaceDrawContext::setupDstProxyView(const GrOp& op, GrDstProxyView* dst
|
||||
dstProxyView->setDstSampleFlags(dstSampleFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
GrOpsTask* GrSurfaceDrawContext::replaceOpsTaskIfModifiesColor() {
|
||||
if (!this->getOpsTask()->isColorNoOp()) {
|
||||
this->replaceOpsTask();
|
||||
}
|
||||
return this->getOpsTask();
|
||||
}
|
||||
|
||||
|
@ -712,7 +712,11 @@ private:
|
||||
// value is false then a texture copy could not be made.
|
||||
//
|
||||
// The op should have already had setClippedBounds called on it.
|
||||
bool SK_WARN_UNUSED_RESULT setupDstProxyView(const GrOp& op, GrDstProxyView* result);
|
||||
bool SK_WARN_UNUSED_RESULT setupDstProxyView(const SkRect& opBounds,
|
||||
bool opRequiresMSAA,
|
||||
GrDstProxyView* result);
|
||||
|
||||
GrOpsTask* replaceOpsTaskIfModifiesColor();
|
||||
|
||||
SkGlyphRunListPainter* glyphPainter() { return &fGlyphPainter; }
|
||||
|
||||
|
@ -306,15 +306,20 @@ GrOpsTask* GrSurfaceFillContext::getOpsTask() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
if (!fOpsTask || fOpsTask->isClosed()) {
|
||||
sk_sp<GrOpsTask> newOpsTask = this->drawingManager()->newOpsTask(
|
||||
this->writeSurfaceView(), this->arenas(), fFlushTimeOpsTask);
|
||||
this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
|
||||
fOpsTask = std::move(newOpsTask);
|
||||
this->replaceOpsTask();
|
||||
}
|
||||
SkASSERT(!fOpsTask->isClosed());
|
||||
return fOpsTask.get();
|
||||
}
|
||||
|
||||
GrOpsTask* GrSurfaceFillContext::replaceOpsTask() {
|
||||
sk_sp<GrOpsTask> newOpsTask = this->drawingManager()->newOpsTask(
|
||||
this->writeSurfaceView(), this->arenas(), fFlushTimeOpsTask);
|
||||
this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
|
||||
fOpsTask = std::move(newOpsTask);
|
||||
return fOpsTask.get();
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void GrSurfaceFillContext::onValidate() const {
|
||||
if (fOpsTask && !fOpsTask->isClosed()) {
|
||||
|
@ -200,6 +200,8 @@ protected:
|
||||
|
||||
void addOp(GrOp::Owner);
|
||||
|
||||
GrOpsTask* replaceOpsTask();
|
||||
|
||||
private:
|
||||
sk_sp<GrArenas> arenas() { return fWriteView.proxy()->asRenderTargetProxy()->arenas(); }
|
||||
|
||||
|
@ -19,6 +19,15 @@ constexpr static SkPMColor4f kTransYellow = {.5f,.5f,.0f,.5f};
|
||||
constexpr static SkPMColor4f kTransCyan = {.0f,.5f,.5f,.5f};
|
||||
constexpr static int w=10, h=10;
|
||||
|
||||
static void draw_paint_with_aa(GrSurfaceDrawContext* sdc, const SkPMColor4f& color,
|
||||
SkBlendMode blendMode) {
|
||||
GrPaint paint;
|
||||
paint.setColor4f(color);
|
||||
paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
|
||||
sdc->drawRect(nullptr, std::move(paint), GrAA::kYes, SkMatrix::I(), SkRect::MakeIWH(w, h),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
static void draw_paint_with_dmsaa(GrSurfaceDrawContext* sdc, const SkPMColor4f& color,
|
||||
SkBlendMode blendMode) {
|
||||
// drawVertices should always trigger dmsaa, but draw something non-rectangular just to be 100%
|
||||
@ -89,3 +98,81 @@ DEF_GPUTEST_FOR_CONTEXTS(DMSAA_preserve_contents,
|
||||
|
||||
check_sdc_color(reporter, sdc.get(), ctx, dstColor);
|
||||
}
|
||||
|
||||
static void require_dst_reads(GrContextOptions* options) {
|
||||
options->fSuppressAdvancedBlendEquations = true;
|
||||
options->fSuppressFramebufferFetch = true;
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_CONTEXTS(DMSAA_dst_read, &sk_gpu_test::GrContextFactory::IsRenderingContext,
|
||||
reporter, ctxInfo, require_dst_reads) {
|
||||
auto ctx = ctxInfo.directContext();
|
||||
auto sdc = GrSurfaceDrawContext::Make(ctx, GrColorType::kRGBA_8888, nullptr,
|
||||
SkBackingFit::kApprox, {w, h}, kDMSAAProps);
|
||||
|
||||
// Initialize the texture and dmsaa attachment with transparent.
|
||||
draw_paint_with_dmsaa(sdc.get(), SK_PMColor4fTRANSPARENT, SkBlendMode::kSrc);
|
||||
check_sdc_color(reporter, sdc.get(), ctx, SK_PMColor4fTRANSPARENT);
|
||||
|
||||
sdc->clear(SK_PMColor4fWHITE);
|
||||
SkPMColor4f dstColor = SK_PMColor4fWHITE;
|
||||
|
||||
draw_paint_with_dmsaa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
|
||||
|
||||
draw_paint_with_dmsaa(sdc.get(), kTransCyan, SkBlendMode::kDarken);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransCyan, dstColor);
|
||||
|
||||
check_sdc_color(reporter, sdc.get(), ctx, dstColor);
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_CONTEXTS(DMSAA_aa_dst_read_after_dmsaa,
|
||||
&sk_gpu_test::GrContextFactory::IsRenderingContext, reporter, ctxInfo,
|
||||
require_dst_reads) {
|
||||
auto ctx = ctxInfo.directContext();
|
||||
auto sdc = GrSurfaceDrawContext::Make(ctx, GrColorType::kRGBA_8888, nullptr,
|
||||
SkBackingFit::kApprox, {w, h}, kDMSAAProps);
|
||||
|
||||
// Initialize the texture and dmsaa attachment with transparent.
|
||||
draw_paint_with_dmsaa(sdc.get(), SK_PMColor4fTRANSPARENT, SkBlendMode::kSrc);
|
||||
check_sdc_color(reporter, sdc.get(), ctx, SK_PMColor4fTRANSPARENT);
|
||||
|
||||
sdc->clear(SK_PMColor4fWHITE);
|
||||
SkPMColor4f dstColor = SK_PMColor4fWHITE;
|
||||
|
||||
draw_paint_with_dmsaa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
|
||||
|
||||
// Draw with aa after dmsaa. This should break up the render pass and issue a texture barrier.
|
||||
draw_paint_with_aa(sdc.get(), kTransCyan, SkBlendMode::kDarken);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransCyan, dstColor);
|
||||
|
||||
check_sdc_color(reporter, sdc.get(), ctx, dstColor);
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_CONTEXTS(DMSAA_dst_read_with_existing_barrier,
|
||||
&sk_gpu_test::GrContextFactory::IsRenderingContext, reporter, ctxInfo,
|
||||
require_dst_reads) {
|
||||
auto ctx = ctxInfo.directContext();
|
||||
auto sdc = GrSurfaceDrawContext::Make(ctx, GrColorType::kRGBA_8888, nullptr,
|
||||
SkBackingFit::kApprox, {w, h}, kDMSAAProps);
|
||||
|
||||
// Initialize the texture and dmsaa attachment with transparent.
|
||||
draw_paint_with_dmsaa(sdc.get(), SK_PMColor4fTRANSPARENT, SkBlendMode::kSrc);
|
||||
check_sdc_color(reporter, sdc.get(), ctx, SK_PMColor4fTRANSPARENT);
|
||||
|
||||
sdc->clear(SK_PMColor4fWHITE);
|
||||
SkPMColor4f dstColor = SK_PMColor4fWHITE;
|
||||
|
||||
// Blend to the texture (not the dmsaa attachment) with a dst read. This creates a texture
|
||||
// barrier.
|
||||
draw_paint_with_aa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
|
||||
|
||||
// Blend to the msaa attachment _without_ a dst read. This ensures we respect the prior texture
|
||||
// barrier by splitting the opsTask.
|
||||
draw_paint_with_dmsaa(sdc.get(), kTransCyan, SkBlendMode::kSrcOver);
|
||||
dstColor = SkBlendMode_Apply(SkBlendMode::kSrcOver, kTransCyan, dstColor);
|
||||
|
||||
check_sdc_color(reporter, sdc.get(), ctx, dstColor);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user