Add support for vulkan non coherent advanced blends.

There are basically 3 parts to this change.
1) Implement GrVkGpu::xferBarrier virtual
2) Plumbing the need of an xferBarrier from ProgramInfo when getting a
render pass.
3) Tracking the need for an xferBarrier on GrOpsTask via
GrProcessorSet::Analysis

Bug: skia:10409
Change-Id: I6ab8f36719b3a4db576535eb6ed1c579ae34b7a4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/310439
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Greg Daniel 2020-08-14 14:03:50 -04:00 committed by Skia Commit-Bot
parent 13ec544d3f
commit 9a18b08981
26 changed files with 113 additions and 45 deletions

View File

@ -359,7 +359,8 @@ public:
const SkIRect& bounds, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) = 0; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) = 0;
// Called by GrDrawingManager when flushing. // Called by GrDrawingManager when flushing.
// Provides a hook for post-flush actions (e.g. Vulkan command buffer submits). This will also // Provides a hook for post-flush actions (e.g. Vulkan command buffer submits). This will also

View File

@ -466,7 +466,8 @@ static GrOpsRenderPass* create_render_pass(
GrGpu* gpu, GrRenderTarget* rt, GrStencilAttachment* stencil, GrSurfaceOrigin origin, GrGpu* gpu, GrRenderTarget* rt, GrStencilAttachment* stencil, GrSurfaceOrigin origin,
const SkIRect& bounds, GrLoadOp colorLoadOp, const SkPMColor4f& loadClearColor, const SkIRect& bounds, GrLoadOp colorLoadOp, const SkPMColor4f& loadClearColor,
GrLoadOp stencilLoadOp, GrStoreOp stencilStoreOp, GrLoadOp stencilLoadOp, GrStoreOp stencilStoreOp,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
const GrOpsRenderPass::LoadAndStoreInfo kColorLoadStoreInfo { const GrOpsRenderPass::LoadAndStoreInfo kColorLoadStoreInfo {
colorLoadOp, colorLoadOp,
GrStoreOp::kStore, GrStoreOp::kStore,
@ -484,7 +485,8 @@ static GrOpsRenderPass* create_render_pass(
}; };
return gpu->getOpsRenderPass(rt, stencil, origin, bounds, return gpu->getOpsRenderPass(rt, stencil, origin, bounds,
kColorLoadStoreInfo, stencilLoadAndStoreInfo, sampledProxies); kColorLoadStoreInfo, stencilLoadAndStoreInfo, sampledProxies,
usesXferBarriers);
} }
// TODO: this is where GrOp::renderTarget is used (which is fine since it // TODO: this is where GrOp::renderTarget is used (which is fine since it
@ -569,7 +571,7 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) {
GrOpsRenderPass* renderPass = create_render_pass( GrOpsRenderPass* renderPass = create_render_pass(
flushState->gpu(), proxy->peekRenderTarget(), stencil, this->target(0).origin(), flushState->gpu(), proxy->peekRenderTarget(), stencil, this->target(0).origin(),
fClippedContentBounds, fColorLoadOp, fLoadClearColor, stencilLoadOp, stencilStoreOp, fClippedContentBounds, fColorLoadOp, fLoadClearColor, stencilLoadOp, stencilStoreOp,
fSampledProxies); fSampledProxies, fUsesXferBarriers);
if (!renderPass) { if (!renderPass) {
return false; return false;
} }

View File

@ -115,7 +115,14 @@ public:
if (dstProxyView.proxy()) { if (dstProxyView.proxy()) {
this->addSampledTexture(dstProxyView.proxy()); this->addSampledTexture(dstProxyView.proxy());
addDependency(dstProxyView.proxy(), GrMipmapped::kNo); addDependency(dstProxyView.proxy(), GrMipmapped::kNo);
if (this->target(0).asTextureProxy() == dstProxyView.proxy()) {
// Since we are sampling and drawing to the same surface we will need to use
// texture barriers.
fUsesXferBarriers |= true;
} }
}
fUsesXferBarriers |= processorAnalysis.usesNonCoherentHWBlending();
this->recordOp(std::move(op), processorAnalysis, clip.doesClip() ? &clip : nullptr, this->recordOp(std::move(op), processorAnalysis, clip.doesClip() ? &clip : nullptr,
&dstProxyView, caps); &dstProxyView, caps);
@ -313,6 +320,8 @@ private:
SkIRect fLastDevClipBounds; SkIRect fLastDevClipBounds;
int fLastClipNumAnalyticElements; int fLastClipNumAnalyticElements;
bool fUsesXferBarriers = false;
// For ops/opsTask we have mean: 5 stdDev: 28 // For ops/opsTask we have mean: 5 stdDev: 28
SkSTArray<25, OpChain> fOpChains; SkSTArray<25, OpChain> fOpChains;

View File

@ -160,6 +160,8 @@ GrProcessorSet::Analysis GrProcessorSet::finalize(
SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithCoverageAsAlpha); SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithCoverageAsAlpha);
analysis.fRequiresNonOverlappingDraws = analysis.fRequiresNonOverlappingDraws =
SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresNonOverlappingDraws); SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresNonOverlappingDraws);
analysis.fUsesNonCoherentHWBlending =
SkToBool(props & GrXPFactory::AnalysisProperties::kUsesNonCoherentHWBlending);
if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) { if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
colorFPsToEliminate = this->hasColorFragmentProcessor() ? 1 : 0; colorFPsToEliminate = this->hasColorFragmentProcessor() ? 1 : 0;
analysis.fInputColorType = analysis.fInputColorType =

View File

@ -85,6 +85,7 @@ public:
bool inputColorIsOverridden() const { bool inputColorIsOverridden() const {
return fInputColorType == kOverridden_InputColorType; return fInputColorType == kOverridden_InputColorType;
} }
bool usesNonCoherentHWBlending() const { return fUsesNonCoherentHWBlending; }
private: private:
constexpr Analysis(Empty) constexpr Analysis(Empty)
@ -94,6 +95,7 @@ public:
, fRequiresNonOverlappingDraws(false) , fRequiresNonOverlappingDraws(false)
, fHasColorFragmentProcessor(false) , fHasColorFragmentProcessor(false)
, fIsInitialized(true) , fIsInitialized(true)
, fUsesNonCoherentHWBlending(false)
, fInputColorType(kOriginal_InputColorType) {} , fInputColorType(kOriginal_InputColorType) {}
enum InputColorType : uint32_t { enum InputColorType : uint32_t {
kOriginal_InputColorType, kOriginal_InputColorType,
@ -111,6 +113,7 @@ public:
PackedBool fRequiresNonOverlappingDraws : 1; PackedBool fRequiresNonOverlappingDraws : 1;
PackedBool fHasColorFragmentProcessor : 1; PackedBool fHasColorFragmentProcessor : 1;
PackedBool fIsInitialized : 1; PackedBool fIsInitialized : 1;
PackedBool fUsesNonCoherentHWBlending : 1;
PackedInputColorType fInputColorType : 2; PackedInputColorType fInputColorType : 2;
friend class GrProcessorSet; friend class GrProcessorSet;

View File

@ -277,6 +277,10 @@ public:
* texture or because we need an xfer barrier). * texture or because we need an xfer barrier).
*/ */
kRequiresNonOverlappingDraws = 0x20, kRequiresNonOverlappingDraws = 0x20,
/**
* If set the draw will use fixed function non coherent advanced blends.
*/
kUsesNonCoherentHWBlending = 0x40,
}; };
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties); GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties);

View File

@ -106,7 +106,8 @@ GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
if (!fCachedOpsRenderPass) { if (!fCachedOpsRenderPass) {
fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this)); fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
} }

View File

@ -84,7 +84,8 @@ public:
GrSurfaceOrigin, const SkIRect&, GrSurfaceOrigin, const SkIRect&,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
void addResourceBarriers(sk_sp<GrManagedResource> resource, void addResourceBarriers(sk_sp<GrManagedResource> resource,
int numBarriers, int numBarriers,

View File

@ -140,7 +140,8 @@ GrOpsRenderPass* GrDawnGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
fOpsRenderPass.reset(new GrDawnOpsRenderPass(this, rt, origin, colorInfo, stencilInfo)); fOpsRenderPass.reset(new GrDawnOpsRenderPass(this, rt, origin, colorInfo, stencilInfo));
return fOpsRenderPass.get(); return fOpsRenderPass.get();
} }

View File

@ -68,7 +68,8 @@ public:
GrSurfaceOrigin, const SkIRect& bounds, GrSurfaceOrigin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
SkSL::Compiler* shaderCompiler() const { SkSL::Compiler* shaderCompiler() const {
return fCompiler.get(); return fCompiler.get();

View File

@ -357,7 +357,8 @@ GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
return AnalysisProperties::kCompatibleWithCoverageAsAlpha; return AnalysisProperties::kCompatibleWithCoverageAsAlpha;
} else { } else {
return AnalysisProperties::kCompatibleWithCoverageAsAlpha | return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
AnalysisProperties::kRequiresNonOverlappingDraws; AnalysisProperties::kRequiresNonOverlappingDraws |
AnalysisProperties::kUsesNonCoherentHWBlending;
} }
} }
return AnalysisProperties::kCompatibleWithCoverageAsAlpha | return AnalysisProperties::kCompatibleWithCoverageAsAlpha |

View File

@ -2203,7 +2203,8 @@ GrOpsRenderPass* GrGLGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
if (!fCachedOpsRenderPass) { if (!fCachedOpsRenderPass) {
fCachedOpsRenderPass = std::make_unique<GrGLOpsRenderPass>(this); fCachedOpsRenderPass = std::make_unique<GrGLOpsRenderPass>(this);
} }

View File

@ -124,7 +124,8 @@ public:
GrSurfaceOrigin, const SkIRect&, GrSurfaceOrigin, const SkIRect&,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
void invalidateBoundRenderTarget() { void invalidateBoundRenderTarget() {
fHWBoundRenderTargetUniqueID.makeInvalid(); fHWBoundRenderTargetUniqueID.makeInvalid();

View File

@ -57,7 +57,8 @@ GrOpsRenderPass* GrMockGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
return new GrMockOpsRenderPass(this, rt, origin, colorInfo); return new GrMockOpsRenderPass(this, rt, origin, colorInfo);
} }

View File

@ -31,7 +31,8 @@ public:
const SkIRect&, const SkIRect&,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; } GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence) override { return true; } bool waitFence(GrFence) override { return true; }

View File

@ -88,7 +88,8 @@ public:
GrSurfaceOrigin, const SkIRect& bounds, GrSurfaceOrigin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
SkSL::Compiler* shaderCompiler() const { return fCompiler.get(); } SkSL::Compiler* shaderCompiler() const { return fCompiler.get(); }

View File

@ -175,7 +175,8 @@ GrOpsRenderPass* GrMtlGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
return new GrMtlOpsRenderPass(this, renderTarget, origin, colorInfo, stencilInfo); return new GrMtlOpsRenderPass(this, renderTarget, origin, colorInfo, stencilInfo);
} }

View File

@ -592,9 +592,7 @@ void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
if (blendFeatures && blendFeatures->advancedBlendCoherentOperations == VK_TRUE) { if (blendFeatures && blendFeatures->advancedBlendCoherentOperations == VK_TRUE) {
fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport; fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport;
} else { } else {
// TODO: Currently non coherent blends are not supported in our vulkan backend. They fBlendEquationSupport = kAdvanced_BlendEquationSupport;
// require us to support self dependencies in our render passes.
// fBlendEquationSupport = kAdvanced_BlendEquationSupport;
} }
} }
} }
@ -1709,14 +1707,17 @@ GrProgramDesc GrVkCaps::makeDesc(GrRenderTarget* rt, const GrProgramInfo& progra
// GrVkPipelineStateBuilder.cpp). // GrVkPipelineStateBuilder.cpp).
b.add32(GrVkGpu::kShader_PersistentCacheKeyType); b.add32(GrVkGpu::kShader_PersistentCacheKeyType);
bool usesXferBarrier = false; // TODO: get this from GrProgramInfo // Currently we only support blend barriers with the advanced blend function. Thus we pass in
// nullptr for the texture.
auto barrierType = programInfo.pipeline().xferBarrierType(nullptr, *this);
bool usesXferBarriers = barrierType == kBlend_GrXferBarrierType;
if (rt) { if (rt) {
GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt; GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt;
bool needsStencil = programInfo.numStencilSamples() || programInfo.isStencilEnabled(); bool needsStencil = programInfo.numStencilSamples() || programInfo.isStencilEnabled();
// TODO: support failure in getSimpleRenderPass // TODO: support failure in getSimpleRenderPass
const GrVkRenderPass* rp = vkRT->getSimpleRenderPass(needsStencil, usesXferBarrier); const GrVkRenderPass* rp = vkRT->getSimpleRenderPass(needsStencil, usesXferBarriers);
SkASSERT(rp); SkASSERT(rp);
rp->genKey(&b); rp->genKey(&b);
@ -1729,7 +1730,7 @@ GrProgramDesc GrVkCaps::makeDesc(GrRenderTarget* rt, const GrProgramInfo& progra
GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo, GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo,
&attachmentsDescriptor, &attachmentsDescriptor,
&attachmentFlags); &attachmentFlags);
SkASSERT(rp->isCompatible(attachmentsDescriptor, attachmentFlags, usesXferBarrier)); SkASSERT(rp->isCompatible(attachmentsDescriptor, attachmentFlags, usesXferBarriers));
} }
#endif #endif
} else { } else {
@ -1742,7 +1743,7 @@ GrProgramDesc GrVkCaps::makeDesc(GrRenderTarget* rt, const GrProgramInfo& progra
// kExternal_AttachmentFlag is only set for wrapped secondary command buffers - which // kExternal_AttachmentFlag is only set for wrapped secondary command buffers - which
// will always go through the above 'rt' path (i.e., we can always pass 0 as the final // will always go through the above 'rt' path (i.e., we can always pass 0 as the final
// parameter to GenKey). // parameter to GenKey).
GrVkRenderPass::GenKey(&b, attachmentFlags, attachmentsDescriptor, usesXferBarrier, 0); GrVkRenderPass::GenKey(&b, attachmentFlags, attachmentsDescriptor, usesXferBarriers, 0);
} }
GrStencilSettings stencil = programInfo.nonGLStencilSettings(); GrStencilSettings stencil = programInfo.nonGLStencilSettings();

View File

@ -97,18 +97,28 @@ void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu,
void* barrier) { void* barrier) {
SkASSERT(!this->isWrapped()); SkASSERT(!this->isWrapped());
SkASSERT(fIsActive); SkASSERT(fIsActive);
#ifdef SK_DEBUG
// For images we can have barriers inside of render passes but they require us to add more // For images we can have barriers inside of render passes but they require us to add more
// support in subpasses which need self dependencies to have barriers inside them. Also, we can // support in subpasses which need self dependencies to have barriers inside them. Also, we can
// never have buffer barriers inside of a render pass. For now we will just assert that we are // never have buffer barriers inside of a render pass. For now we will just assert that we are
// not in a render pass. // not in a render pass.
SkASSERT(!fActiveRenderPass); bool isValidSubpassBarrier = false;
if (barrierType == kImageMemory_BarrierType) {
VkImageMemoryBarrier* imgBarrier = static_cast<VkImageMemoryBarrier*>(barrier);
isValidSubpassBarrier = (imgBarrier->newLayout == imgBarrier->oldLayout) &&
(imgBarrier->srcQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) &&
(imgBarrier->dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) &&
byRegion;
}
SkASSERT(!fActiveRenderPass || isValidSubpassBarrier);
#endif
if (barrierType == kBufferMemory_BarrierType) { if (barrierType == kBufferMemory_BarrierType) {
const VkBufferMemoryBarrier* barrierPtr = reinterpret_cast<VkBufferMemoryBarrier*>(barrier); const VkBufferMemoryBarrier* barrierPtr = static_cast<VkBufferMemoryBarrier*>(barrier);
fBufferBarriers.push_back(*barrierPtr); fBufferBarriers.push_back(*barrierPtr);
} else { } else {
SkASSERT(barrierType == kImageMemory_BarrierType); SkASSERT(barrierType == kImageMemory_BarrierType);
const VkImageMemoryBarrier* barrierPtr = reinterpret_cast<VkImageMemoryBarrier*>(barrier); const VkImageMemoryBarrier* barrierPtr = static_cast<VkImageMemoryBarrier*>(barrier);
// We need to check if we are adding a pipeline barrier that covers part of the same // We need to check if we are adding a pipeline barrier that covers part of the same
// subresource range as a barrier that is already in current batch. If it does, then we must // subresource range as a barrier that is already in current batch. If it does, then we must
// submit the first batch because the vulkan spec does not define a specific ordering for // submit the first batch because the vulkan spec does not define a specific ordering for
@ -136,7 +146,6 @@ void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu,
fImageBarriers.push_back(*barrierPtr); fImageBarriers.push_back(*barrierPtr);
} }
fBarriersByRegion |= byRegion; fBarriersByRegion |= byRegion;
fSrcStageMask = fSrcStageMask | srcStageMask; fSrcStageMask = fSrcStageMask | srcStageMask;
fDstStageMask = fDstStageMask | dstStageMask; fDstStageMask = fDstStageMask | dstStageMask;
@ -144,9 +153,12 @@ void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu,
if (resource) { if (resource) {
this->addResource(resource); this->addResource(resource);
} }
if (fActiveRenderPass) {
this->submitPipelineBarriers(gpu, true);
}
} }
void GrVkCommandBuffer::submitPipelineBarriers(const GrVkGpu* gpu) { void GrVkCommandBuffer::submitPipelineBarriers(const GrVkGpu* gpu, bool forSelfDependency) {
SkASSERT(fIsActive); SkASSERT(fIsActive);
// Currently we never submit a pipeline barrier without at least one memory barrier. // Currently we never submit a pipeline barrier without at least one memory barrier.
@ -155,7 +167,7 @@ void GrVkCommandBuffer::submitPipelineBarriers(const GrVkGpu* gpu) {
// support in subpasses which need self dependencies to have barriers inside them. Also, we // support in subpasses which need self dependencies to have barriers inside them. Also, we
// can never have buffer barriers inside of a render pass. For now we will just assert that // can never have buffer barriers inside of a render pass. For now we will just assert that
// we are not in a render pass. // we are not in a render pass.
SkASSERT(!fActiveRenderPass); SkASSERT(!fActiveRenderPass || forSelfDependency);
SkASSERT(!this->isWrapped()); SkASSERT(!this->isWrapped());
SkASSERT(fSrcStageMask && fDstStageMask); SkASSERT(fSrcStageMask && fDstStageMask);

View File

@ -145,7 +145,7 @@ protected:
void addingWork(const GrVkGpu* gpu); void addingWork(const GrVkGpu* gpu);
void submitPipelineBarriers(const GrVkGpu* gpu); void submitPipelineBarriers(const GrVkGpu* gpu, bool forSelfDependency = false);
SkTDArray<const GrManagedResource*> fTrackedResources; SkTDArray<const GrManagedResource*> fTrackedResources;
SkTDArray<const GrRecycledResource*> fTrackedRecycledResources; SkTDArray<const GrRecycledResource*> fTrackedRecycledResources;

View File

@ -317,15 +317,14 @@ GrOpsRenderPass* GrVkGpu::getOpsRenderPass(
GrSurfaceOrigin origin, const SkIRect& bounds, GrSurfaceOrigin origin, const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) {
if (!fCachedOpsRenderPass) { if (!fCachedOpsRenderPass) {
fCachedOpsRenderPass = std::make_unique<GrVkOpsRenderPass>(this); fCachedOpsRenderPass = std::make_unique<GrVkOpsRenderPass>(this);
} }
bool usesXferBarrier = false; // TODO: we should be passing this value
if (!fCachedOpsRenderPass->set(rt, stencil, origin, bounds, colorInfo, stencilInfo, if (!fCachedOpsRenderPass->set(rt, stencil, origin, bounds, colorInfo, stencilInfo,
sampledProxies, usesXferBarrier)) { sampledProxies, usesXferBarriers)) {
return nullptr; return nullptr;
} }
return fCachedOpsRenderPass.get(); return fCachedOpsRenderPass.get();
@ -1877,6 +1876,25 @@ void GrVkGpu::querySampleLocations(GrRenderTarget* renderTarget,
} }
} }
void GrVkGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType barrierType) {
SkASSERT(barrierType == kBlend_GrXferBarrierType);
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
barrier.oldLayout = vkRT->currentLayout();
barrier.newLayout = vkRT->currentLayout();
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = vkRT->image();
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, vkRT->mipLevels(), 0, 1};
this->addImageMemoryBarrier(vkRT->resource(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, true, &barrier);
}
void GrVkGpu::deleteBackendTexture(const GrBackendTexture& tex) { void GrVkGpu::deleteBackendTexture(const GrBackendTexture& tex) {
SkASSERT(GrBackendApi::kVulkan == tex.fBackend); SkASSERT(GrBackendApi::kVulkan == tex.fBackend);
@ -1894,7 +1912,10 @@ bool GrVkGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInf
GrVkRenderTarget::ReconstructAttachmentsDescriptor(this->vkCaps(), programInfo, GrVkRenderTarget::ReconstructAttachmentsDescriptor(this->vkCaps(), programInfo,
&attachmentsDescriptor, &attachmentFlags); &attachmentsDescriptor, &attachmentFlags);
bool willReadDst = false; // TODO: get this from GrProgramInfo // Currently we only support blend barriers with the advanced blend function. Thus we pass in
// nullptr for the texture.
auto barrierType = programInfo.pipeline().xferBarrierType(nullptr, *this->caps());
bool willReadDst = barrierType == kBlend_GrXferBarrierType;
sk_sp<const GrVkRenderPass> renderPass(this->resourceProvider().findCompatibleRenderPass( sk_sp<const GrVkRenderPass> renderPass(this->resourceProvider().findCompatibleRenderPass(
&attachmentsDescriptor, &attachmentsDescriptor,
attachmentFlags, attachmentFlags,

View File

@ -75,7 +75,7 @@ public:
void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override; void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override;
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} void xferBarrier(GrRenderTarget*, GrXferBarrierType) override;
bool setBackendTextureState(const GrBackendTexture&, bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&, const GrBackendSurfaceMutableState&,
@ -110,7 +110,8 @@ public:
GrSurfaceOrigin, const SkIRect&, GrSurfaceOrigin, const SkIRect&,
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarriers) override;
void addBufferMemoryBarrier(const GrManagedResource*, void addBufferMemoryBarrier(const GrManagedResource*,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags srcStageMask,

View File

@ -194,7 +194,7 @@ void GrVkImage::setImageLayoutAndQueueIndex(const GrVkGpu* gpu,
fInfo.fImage, // image fInfo.fImage, // image
{ aspectFlags, 0, fInfo.fLevelCount, 0, 1 } // subresourceRange { aspectFlags, 0, fInfo.fLevelCount, 0, 1 } // subresourceRange
}; };
SkASSERT(srcAccessMask == imageMemoryBarrier.srcAccessMask);
gpu->addImageMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion, gpu->addImageMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion,
&imageMemoryBarrier); &imageMemoryBarrier);

View File

@ -212,7 +212,7 @@ bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrStencilAttachment* stencil,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies, const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarrier) { bool usesXferBarriers) {
SkASSERT(!fRenderTarget); SkASSERT(!fRenderTarget);
SkASSERT(fGpu == rt->getContext()->priv().getGpu()); SkASSERT(fGpu == rt->getContext()->priv().getGpu());
@ -243,7 +243,7 @@ bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrStencilAttachment* stencil,
SkASSERT(bounds.isEmpty() || SkIRect::MakeWH(rt->width(), rt->height()).contains(bounds)); SkASSERT(bounds.isEmpty() || SkIRect::MakeWH(rt->width(), rt->height()).contains(bounds));
fBounds = bounds; fBounds = bounds;
fUsesXferBarriers = usesXferBarrier; fUsesXferBarriers = usesXferBarriers;
if (this->wrapsSecondaryCommandBuffer()) { if (this->wrapsSecondaryCommandBuffer()) {
return this->initWrapped(); return this->initWrapped();

View File

@ -36,7 +36,7 @@ public:
const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&,
const SkTArray<GrSurfaceProxy*, true>& sampledProxies, const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
bool usesXferBarrier); bool usesXferBarriers);
void reset(); void reset();
void submit(); void submit();

View File

@ -23,6 +23,7 @@ void setup_vk_attachment_description(VkAttachmentDescription* attachment,
SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples)); SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples));
switch (layout) { switch (layout) {
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
case VK_IMAGE_LAYOUT_GENERAL:
attachment->loadOp = desc.fLoadStoreOps.fLoadOp; attachment->loadOp = desc.fLoadStoreOps.fLoadOp;
attachment->storeOp = desc.fLoadStoreOps.fStoreOp; attachment->storeOp = desc.fLoadStoreOps.fStoreOp;
attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@ -75,7 +76,7 @@ GrVkRenderPass* GrVkRenderPass::Create(GrVkGpu* gpu,
// need to create a self dependency for that subpass so that we can use barriers. Finally, the // need to create a self dependency for that subpass so that we can use barriers. Finally, the
// color attachment will need to be set to the GENERAL layout since it will be used for reading // color attachment will need to be set to the GENERAL layout since it will be used for reading
// and writing here. // and writing here.
SkASSERT(!needsSelfDependency); SkASSERT(!needsSelfDependency || gpu->caps()->advancedBlendEquationSupport());
uint32_t numAttachments = attachmentsDescriptor->fAttachmentCount; uint32_t numAttachments = attachmentsDescriptor->fAttachmentCount;
// Attachment descriptions to be set on the render pass // Attachment descriptions to be set on the render pass