Use GrVkFramebuffer throughout GrVkOpsRenderPass instead of GrVkRT.
This also connects a lot of the wires needed to use dynamic MSAA in
vulkan. By using the framebuffer object in the render pass we can figure
out the specific framebuffer we want in one place, GrVkGpu::onGetOpsRenderPass,
and then the render pass itself doesn't need any explicit knowledge of
dmsaa stuff.
Bug: skia:11809
Change-Id: I3e4e71fa6f9536fdaf915d5369a2f8a24bf48c9b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/397156
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 7db871e..83f705c 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -458,19 +458,15 @@
bool GrVkPrimaryCommandBuffer::beginRenderPass(GrVkGpu* gpu,
const GrVkRenderPass* renderPass,
+ sk_sp<const GrVkFramebuffer> framebuffer,
const VkClearValue clearValues[],
GrVkRenderTarget* target,
const SkIRect& bounds,
bool forSecondaryCB) {
SkASSERT(fIsActive);
SkASSERT(!fActiveRenderPass);
- SkASSERT(renderPass->isCompatible(*target, renderPass->selfDependencyFlags(),
- renderPass->loadFromResolve()));
- const GrVkFramebuffer* framebuffer = target->getFramebuffer(*renderPass);
- if (!framebuffer) {
- return false;
- }
+ SkASSERT(framebuffer);
this->addingWork(gpu);
@@ -494,7 +490,7 @@
GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents));
fActiveRenderPass = renderPass;
this->addResource(renderPass);
- this->addResource(framebuffer);
+ this->addResource(std::move(framebuffer));
this->addGrSurface(sk_ref_sp(target));
return true;
}
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 8234063..e018ee2 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -216,7 +216,8 @@
// Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
// in the render pass.
bool beginRenderPass(GrVkGpu* gpu,
- const GrVkRenderPass* renderPass,
+ const GrVkRenderPass*,
+ sk_sp<const GrVkFramebuffer>,
const VkClearValue clearValues[],
GrVkRenderTarget* target,
const SkIRect& bounds,
diff --git a/src/gpu/vk/GrVkFramebuffer.cpp b/src/gpu/vk/GrVkFramebuffer.cpp
index ec14134..5dffcc8 100644
--- a/src/gpu/vk/GrVkFramebuffer.cpp
+++ b/src/gpu/vk/GrVkFramebuffer.cpp
@@ -15,7 +15,7 @@
GrVkFramebuffer* GrVkFramebuffer::Create(
GrVkGpu* gpu,
- int width, int height,
+ SkISize dimensions,
const GrVkRenderPass* renderPass,
GrVkAttachment* colorAttachment,
GrVkAttachment* resolveAttachment,
@@ -43,8 +43,8 @@
createInfo.renderPass = renderPass->vkRenderPass();
createInfo.attachmentCount = numAttachments;
createInfo.pAttachments = attachments;
- createInfo.width = width;
- createInfo.height = height;
+ createInfo.width = dimensions.width();
+ createInfo.height = dimensions.height();
createInfo.layers = 1;
VkFramebuffer framebuffer;
@@ -71,7 +71,9 @@
, fColorAttachment(std::move(colorAttachment))
, fResolveAttachment(std::move(resolveAttachment))
, fStencilAttachment(std::move(stencilAttachment))
- , fCompatibleRenderPassHandle(compatibleRPHandle) {}
+ , fCompatibleRenderPassHandle(compatibleRPHandle) {
+ SkASSERT(fCompatibleRenderPassHandle.isValid());
+}
GrVkFramebuffer::GrVkFramebuffer(const GrVkGpu* gpu,
sk_sp<GrVkAttachment> colorAttachment,
diff --git a/src/gpu/vk/GrVkFramebuffer.h b/src/gpu/vk/GrVkFramebuffer.h
index e694917..98df382 100644
--- a/src/gpu/vk/GrVkFramebuffer.h
+++ b/src/gpu/vk/GrVkFramebuffer.h
@@ -21,7 +21,7 @@
class GrVkFramebuffer : public GrVkManagedResource {
public:
static GrVkFramebuffer* Create(GrVkGpu* gpu,
- int width, int height,
+ SkISize dimensions,
const GrVkRenderPass* renderPass,
GrVkAttachment* colorAttachment,
GrVkAttachment* resolveAttachment,
@@ -34,8 +34,12 @@
sk_sp<const GrVkRenderPass> renderPass,
std::unique_ptr<GrVkSecondaryCommandBuffer>);
- VkFramebuffer framebuffer() const { return fFramebuffer; }
+ VkFramebuffer framebuffer() const {
+ SkASSERT(!this->isExternal());
+ return fFramebuffer;
+ }
+ bool isExternal() const { return fExternalRenderPass.get(); }
const GrVkRenderPass* externalRenderPass() const { return fExternalRenderPass.get(); }
std::unique_ptr<GrVkSecondaryCommandBuffer> externalCommandBuffer();
@@ -75,8 +79,6 @@
~GrVkFramebuffer() override;
- bool isExternal() const { return fExternalCommandBuffer.get(); }
-
void freeGPUData() const override;
void releaseResources();
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index f5285b5..f03c892 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -32,6 +32,7 @@
#include "src/gpu/vk/GrVkBuffer.h"
#include "src/gpu/vk/GrVkCommandBuffer.h"
#include "src/gpu/vk/GrVkCommandPool.h"
+#include "src/gpu/vk/GrVkFramebuffer.h"
#include "src/gpu/vk/GrVkImage.h"
#include "src/gpu/vk/GrVkInterface.h"
#include "src/gpu/vk/GrVkMemory.h"
@@ -302,7 +303,7 @@
GrOpsRenderPass* GrVkGpu::onGetOpsRenderPass(
GrRenderTarget* rt,
- bool /*useMSAASurface*/,
+ bool useMSAASurface,
GrAttachment* stencil,
GrSurfaceOrigin origin,
const SkIRect& bounds,
@@ -314,8 +315,61 @@
fCachedOpsRenderPass = std::make_unique<GrVkOpsRenderPass>(this);
}
- if (!fCachedOpsRenderPass->set(rt, stencil, origin, bounds, colorInfo, stencilInfo,
- sampledProxies, renderPassXferBarriers)) {
+ // For the given render target and requested render pass features we need to find a compatible
+ // framebuffer to use for the render pass. Technically it is the underlying VkRenderPass that
+ // is compatible, but that is part of the framebuffer that we get here.
+ GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
+
+ SkASSERT(!useMSAASurface ||
+ (rt->numSamples() > 1 ||
+ (this->vkCaps().preferDiscardableMSAAAttachment() && vkRT->resolveAttachment() &&
+ vkRT->resolveAttachment()->supportsInputAttachmentUsage())));
+
+ // Covert the GrXferBarrierFlags into render pass self dependency flags
+ GrVkRenderPass::SelfDependencyFlags selfDepFlags = GrVkRenderPass::SelfDependencyFlags::kNone;
+ if (renderPassXferBarriers & GrXferBarrierFlags::kBlend) {
+ selfDepFlags |= GrVkRenderPass::SelfDependencyFlags::kForNonCoherentAdvBlend;
+ }
+ if (renderPassXferBarriers & GrXferBarrierFlags::kTexture) {
+ selfDepFlags |= GrVkRenderPass::SelfDependencyFlags::kForInputAttachment;
+ }
+
+ // Figure out if we need a resolve attachment for this render pass. A resolve attachment is
+ // needed if we are using msaa to draw with a discardable msaa attachment. If we are in this
+ // case we also need to update the color load/store ops since we don't want to ever load or
+ // store the msaa color attachment, but may need to for the resolve attachment.
+ GrOpsRenderPass::LoadAndStoreInfo localColorInfo = colorInfo;
+ bool withResolve = false;
+ GrVkRenderPass::LoadFromResolve loadFromResolve = GrVkRenderPass::LoadFromResolve::kNo;
+ GrOpsRenderPass::LoadAndStoreInfo resolveInfo{GrLoadOp::kLoad, GrStoreOp::kStore, {}};
+ if (useMSAASurface && this->vkCaps().preferDiscardableMSAAAttachment() &&
+ vkRT->resolveAttachment() && vkRT->resolveAttachment()->supportsInputAttachmentUsage()) {
+ withResolve = true;
+ localColorInfo.fStoreOp = GrStoreOp::kDiscard;
+ if (colorInfo.fLoadOp == GrLoadOp::kLoad) {
+ loadFromResolve = GrVkRenderPass::LoadFromResolve::kLoad;
+ localColorInfo.fLoadOp = GrLoadOp::kDiscard;
+ } else {
+ resolveInfo.fLoadOp = GrLoadOp::kDiscard;
+ }
+ }
+
+ // Get the framebuffer to use for the render pass
+ sk_sp<GrVkFramebuffer> framebuffer;
+ if (vkRT->wrapsSecondaryCommandBuffer()) {
+ framebuffer = vkRT->externalFramebuffer();
+ } else {
+ auto fb = vkRT->getFramebuffer(withResolve, SkToBool(stencil), selfDepFlags,
+ loadFromResolve);
+ framebuffer = sk_ref_sp(fb);
+ }
+ if (!framebuffer) {
+ return nullptr;
+ }
+
+ if (!fCachedOpsRenderPass->set(rt, std::move(framebuffer), origin, bounds, localColorInfo,
+ stencilInfo, resolveInfo, selfDepFlags, loadFromResolve,
+ sampledProxies)) {
return nullptr;
}
return fCachedOpsRenderPass.get();
@@ -2381,6 +2435,7 @@
}
bool GrVkGpu::beginRenderPass(const GrVkRenderPass* renderPass,
+ sk_sp<const GrVkFramebuffer> framebuffer,
const VkClearValue* colorClear,
GrVkRenderTarget* target,
const SkIRect& renderPassBounds,
@@ -2405,8 +2460,8 @@
clears[stencilIndex].depthStencil.depth = 0.0f;
clears[stencilIndex].depthStencil.stencil = 0;
- return this->currentCommandBuffer()->beginRenderPass(this, renderPass, clears, target,
- renderPassBounds, forSecondaryCB);
+ return this->currentCommandBuffer()->beginRenderPass(
+ this, renderPass, std::move(framebuffer), clears, target, renderPassBounds, forSecondaryCB);
}
void GrVkGpu::endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin,
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 8dbc3c9..e9d5e50 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -24,6 +24,7 @@
class GrVkBuffer;
class GrVkCommandPool;
+class GrVkFramebuffer;
class GrVkMemoryAllocator;
class GrVkPipeline;
class GrVkPipelineState;
@@ -185,6 +186,7 @@
void storeVkPipelineCacheData() override;
bool beginRenderPass(const GrVkRenderPass*,
+ sk_sp<const GrVkFramebuffer>,
const VkClearValue* colorClear,
GrVkRenderTarget*,
const SkIRect& renderPassBounds,
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 7de5f7d..5a32bbb 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -20,6 +20,7 @@
#include "src/gpu/vk/GrVkBuffer.h"
#include "src/gpu/vk/GrVkCommandBuffer.h"
#include "src/gpu/vk/GrVkCommandPool.h"
+#include "src/gpu/vk/GrVkFramebuffer.h"
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkPipeline.h"
#include "src/gpu/vk/GrVkRenderPass.h"
@@ -66,9 +67,6 @@
bool withStencil = fCurrentRenderPass->hasStencilAttachment();
bool withResolve = fCurrentRenderPass->hasResolveAttachment();
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
- GrVkImage* targetImage = vkRT->colorAttachment();
-
if (fSelfDependencyFlags == SelfDependencyFlags::kForInputAttachment) {
// We need to use the GENERAL layout in this case since we'll be using texture barriers
// with an input attachment.
@@ -77,12 +75,13 @@
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkPipelineStageFlags dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- targetImage->setImageLayout(fGpu, VK_IMAGE_LAYOUT_GENERAL, dstAccess, dstStages, false);
+ fFramebuffer->colorAttachment()->setImageLayout(
+ fGpu, VK_IMAGE_LAYOUT_GENERAL, dstAccess, dstStages, false);
} else {
// Change layout of our render target so it can be used as the color attachment.
// TODO: If we know that we will never be blending or loading the attachment we could drop
// the VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
- targetImage->setImageLayout(
+ fFramebuffer->colorAttachment()->setImageLayout(
fGpu,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
@@ -91,7 +90,7 @@
}
if (withResolve) {
- GrVkAttachment* resolveAttachment = vkRT->resolveAttachment();
+ GrVkAttachment* resolveAttachment = fFramebuffer->resolveAttachment();
SkASSERT(resolveAttachment);
if (loadFromResolve == LoadFromResolve::kLoad) {
resolveAttachment->setImageLayout(fGpu,
@@ -111,7 +110,7 @@
// If we are using a stencil attachment we also need to update its layout
if (withStencil) {
- auto* vkStencil = static_cast<GrVkAttachment*>(fRenderTarget->getStencilAttachment());
+ auto* vkStencil = fFramebuffer->stencilAttachment();
SkASSERT(vkStencil);
// We need the write and read access bits since we may load and store the stencil.
@@ -177,18 +176,17 @@
LoadFromResolve loadFromResolve) {
this->setAttachmentLayouts(loadFromResolve);
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
-
bool firstSubpassUsesSecondaryCB =
loadFromResolve != LoadFromResolve::kLoad && SkToBool(fCurrentSecondaryCommandBuffer);
bool useFullBounds = fCurrentRenderPass->hasResolveAttachment() &&
fGpu->vkCaps().mustLoadFullImageWithDiscardableMSAA();
+ auto dimensions = fFramebuffer->colorAttachment()->dimensions();
+
auto nativeBounds = GrNativeRect::MakeIRectRelativeTo(
fOrigin,
- vkRT->height(),
- useFullBounds ? SkIRect::MakeSize(vkRT->dimensions()) : fBounds);
+ dimensions.height(), useFullBounds ? SkIRect::MakeSize(dimensions) : fBounds);
// The bounds we use for the render pass should be of the granularity supported
// by the device.
@@ -199,13 +197,15 @@
adjust_bounds_to_granularity(&adjustedBounds,
nativeBounds,
granularity,
- vkRT->width(),
- vkRT->height());
+ dimensions.width(),
+ dimensions.height());
} else {
adjustedBounds = nativeBounds;
}
- if (!fGpu->beginRenderPass(fCurrentRenderPass, &clearColor, vkRT, adjustedBounds,
+ GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
+
+ if (!fGpu->beginRenderPass(fCurrentRenderPass, fFramebuffer, &clearColor, vkRT, adjustedBounds,
firstSubpassUsesSecondaryCB)) {
if (fCurrentSecondaryCommandBuffer) {
fCurrentSecondaryCommandBuffer->end(fGpu);
@@ -223,10 +223,7 @@
bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
- const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
- std::array<float, 4> clearColor,
- bool withResolve,
- bool withStencil) {
+ const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo) {
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp, &loadOp, &storeOp);
@@ -238,27 +235,13 @@
get_vk_load_store_ops(stencilInfo.fLoadOp, stencilInfo.fStoreOp, &loadOp, &storeOp);
GrVkRenderPass::LoadStoreOps vkStencilOps(loadOp, storeOp);
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
+ GrVkResourceProvider::CompatibleRPHandle rpHandle = fFramebuffer->compatibleRenderPassHandle();
+ SkASSERT(rpHandle.isValid());
+ fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
+ vkColorOps,
+ vkResolveOps,
+ vkStencilOps);
- const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
- vkRT->compatibleRenderPassHandle(withResolve, withStencil, fSelfDependencyFlags,
- fLoadFromResolve);
- if (rpHandle.isValid()) {
- fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
- vkColorOps,
- vkResolveOps,
- vkStencilOps);
- } else {
- fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT,
- vkColorOps,
- vkResolveOps,
- vkStencilOps,
- nullptr,
- withResolve,
- withStencil,
- fSelfDependencyFlags,
- fLoadFromResolve);
- }
if (!fCurrentRenderPass) {
return false;
}
@@ -270,28 +253,25 @@
fCurrentRenderPass = nullptr;
return false;
}
- const GrVkFramebuffer* framebuffer = vkRT->getFramebuffer(
- withResolve, withStencil, fSelfDependencyFlags, fLoadFromResolve);
- fCurrentSecondaryCommandBuffer->begin(fGpu, framebuffer, fCurrentRenderPass);
+ fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass);
}
VkClearValue vkClearColor;
- vkClearColor.color.float32[0] = clearColor[0];
- vkClearColor.color.float32[1] = clearColor[1];
- vkClearColor.color.float32[2] = clearColor[2];
- vkClearColor.color.float32[3] = clearColor[3];
+ vkClearColor.color.float32[0] = colorInfo.fClearColor[0];
+ vkClearColor.color.float32[1] = colorInfo.fClearColor[1];
+ vkClearColor.color.float32[2] = colorInfo.fClearColor[2];
+ vkClearColor.color.float32[3] = colorInfo.fClearColor[3];
return this->beginRenderPass(vkClearColor, fLoadFromResolve);
}
bool GrVkOpsRenderPass::initWrapped() {
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
- SkASSERT(vkRT->wrapsSecondaryCommandBuffer());
- fCurrentRenderPass = vkRT->externalRenderPass();
+ SkASSERT(fFramebuffer->isExternal());
+ fCurrentRenderPass = fFramebuffer->externalRenderPass();
SkASSERT(fCurrentRenderPass);
fCurrentRenderPass->ref();
- fCurrentSecondaryCommandBuffer = vkRT->externalCommandBuffer();
+ fCurrentSecondaryCommandBuffer = fFramebuffer->externalCommandBuffer();
if (!fCurrentSecondaryCommandBuffer) {
return false;
}
@@ -324,8 +304,8 @@
// attachment. However, when we switched to the main subpass it will transition the layout
// internally to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. Thus we need to update our tracking
// of the layout to match the new layout.
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
- vkRT->resolveAttachment()->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ SkASSERT(fFramebuffer->resolveAttachment());
+ fFramebuffer->resolveAttachment()->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
void GrVkOpsRenderPass::submit() {
@@ -339,10 +319,10 @@
// We don't want to actually submit the secondary command buffer if it is wrapped.
if (this->wrapsSecondaryCommandBuffer()) {
- // We pass the ownership of the GrVkSecondaryCommandBuffer to the special wrapped
- // GrVkRenderTarget since it's lifetime matches the lifetime we need to keep the
- // GrManagedResources on the GrVkSecondaryCommandBuffer alive.
- static_cast<GrVkRenderTarget*>(fRenderTarget)->returnExternalGrSecondaryCommandBuffer(
+ // We pass the ownership of the GrVkSecondaryCommandBuffer to the external framebuffer
+ // since it's lifetime matches the lifetime we need to keep the GrManagedResources on the
+ // GrVkSecondaryCommandBuffer alive.
+ fFramebuffer->returnExternalGrSecondaryCommandBuffer(
std::move(fCurrentSecondaryCommandBuffer));
return;
}
@@ -354,13 +334,15 @@
}
bool GrVkOpsRenderPass::set(GrRenderTarget* rt,
- GrAttachment* stencil,
+ sk_sp<GrVkFramebuffer> framebuffer,
GrSurfaceOrigin origin,
const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
- const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
- GrXferBarrierFlags renderPassXferBarriers) {
+ const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
+ GrVkRenderPass::SelfDependencyFlags selfDepFlags,
+ GrVkRenderPass::LoadFromResolve loadFromResolve,
+ const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
SkASSERT(!fRenderTarget);
SkASSERT(fGpu == rt->getContext()->priv().getGpu());
@@ -390,40 +372,21 @@
}
}
- SkASSERT(bounds.isEmpty() || SkIRect::MakeWH(rt->width(), rt->height()).contains(bounds));
+ SkASSERT(framebuffer);
+ fFramebuffer = std::move(framebuffer);
+
+ SkASSERT(bounds.isEmpty() ||
+ SkIRect::MakeSize(fFramebuffer->colorAttachment()->dimensions()).contains(bounds));
fBounds = bounds;
- if (renderPassXferBarriers & GrXferBarrierFlags::kBlend) {
- fSelfDependencyFlags |= GrVkRenderPass::SelfDependencyFlags::kForNonCoherentAdvBlend;
- }
- if (renderPassXferBarriers & GrXferBarrierFlags::kTexture) {
- fSelfDependencyFlags |= GrVkRenderPass::SelfDependencyFlags::kForInputAttachment;
- }
+ fSelfDependencyFlags = selfDepFlags;
+ fLoadFromResolve = loadFromResolve;
if (this->wrapsSecondaryCommandBuffer()) {
return this->initWrapped();
}
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
-
- GrOpsRenderPass::LoadAndStoreInfo localColorInfo = colorInfo;
-
- bool withResolve = false;
- GrOpsRenderPass::LoadAndStoreInfo resolveInfo{GrLoadOp::kLoad, GrStoreOp::kStore, {}};
- if (fRenderTarget->numSamples() > 1 && fGpu->vkCaps().preferDiscardableMSAAAttachment() &&
- vkRT->resolveAttachment() && vkRT->resolveAttachment()->supportsInputAttachmentUsage()) {
- withResolve = true;
- localColorInfo.fStoreOp = GrStoreOp::kDiscard;
- if (colorInfo.fLoadOp == GrLoadOp::kLoad) {
- fLoadFromResolve = LoadFromResolve::kLoad;
- localColorInfo.fLoadOp = GrLoadOp::kDiscard;
- } else {
- resolveInfo.fLoadOp = GrLoadOp::kDiscard;
- }
- }
-
- return this->init(localColorInfo, resolveInfo, stencilInfo, colorInfo.fClearColor, withResolve,
- SkToBool(stencil));
+ return this->init(colorInfo, resolveInfo, stencilInfo);
}
void GrVkOpsRenderPass::reset() {
@@ -440,6 +403,7 @@
fCurrentCBIsEmpty = true;
fRenderTarget = nullptr;
+ fFramebuffer.reset();
fSelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags::kNone;
@@ -452,8 +416,7 @@
}
bool GrVkOpsRenderPass::wrapsSecondaryCommandBuffer() const {
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
- return vkRT->wrapsSecondaryCommandBuffer();
+ return fFramebuffer->isExternal();
}
////////////////////////////////////////////////////////////////////////////////
@@ -464,7 +427,7 @@
return;
}
- GrAttachment* sb = fRenderTarget->getStencilAttachment();
+ GrAttachment* sb = fFramebuffer->stencilAttachment();
// this should only be called internally when we know we have a
// stencil buffer.
SkASSERT(sb);
@@ -485,12 +448,12 @@
// Flip rect if necessary
SkIRect vkRect;
if (!scissor.enabled()) {
- vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
+ vkRect.setXYWH(0, 0, sb->width(), sb->height());
} else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
vkRect = scissor.rect();
} else {
- vkRect.setLTRB(scissor.rect().fLeft, fRenderTarget->height() - scissor.rect().fBottom,
- scissor.rect().fRight, fRenderTarget->height() - scissor.rect().fTop);
+ vkRect.setLTRB(scissor.rect().fLeft, sb->height() - scissor.rect().fBottom,
+ scissor.rect().fRight, sb->height() - scissor.rect().fTop);
}
clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
@@ -527,17 +490,18 @@
// can then reenable this assert assuming we can't get messed up by a waitOp.
//SkASSERT(!fCurrentCBIsEmpty || scissor);
+ auto dimensions = fFramebuffer->colorAttachment()->dimensions();
// We always do a sub rect clear with clearAttachments since we are inside a render pass
VkClearRect clearRect;
// Flip rect if necessary
SkIRect vkRect;
if (!scissor.enabled()) {
- vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
+ vkRect.setSize(dimensions);
} else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
vkRect = scissor.rect();
} else {
- vkRect.setLTRB(scissor.rect().fLeft, fRenderTarget->height() - scissor.rect().fBottom,
- scissor.rect().fRight, fRenderTarget->height() - scissor.rect().fTop);
+ vkRect.setLTRB(scissor.rect().fLeft, dimensions.height() - scissor.rect().fBottom,
+ scissor.rect().fRight, dimensions.height() - scissor.rect().fTop);
}
clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
@@ -562,8 +526,8 @@
void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuffer) {
SkASSERT(!this->wrapsSecondaryCommandBuffer());
- bool withStencil = fCurrentRenderPass->hasStencilAttachment();
- bool withResolve = fCurrentRenderPass->hasResolveAttachment();
+ bool withResolve = fFramebuffer->resolveAttachment();
+ bool withStencil = fFramebuffer->stencilAttachment();
// If we have a resolve attachment we must do a resolve load in the new render pass since we
// broke up the original one. GrProgramInfos were made without any knowledge that the render
@@ -584,28 +548,27 @@
GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE);
- GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
- const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
- vkRT->compatibleRenderPassHandle(withResolve, withStencil, fSelfDependencyFlags,
- loadFromResolve);
SkASSERT(fCurrentRenderPass);
fCurrentRenderPass->unref();
- if (rpHandle.isValid()) {
- fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
- vkColorOps,
- vkResolveOps,
- vkStencilOps);
- } else {
- fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT,
- vkColorOps,
- vkResolveOps,
- vkStencilOps,
- nullptr,
- withResolve,
- withStencil,
- fSelfDependencyFlags,
- loadFromResolve);
+ fCurrentRenderPass = nullptr;
+
+ GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
+ auto fb = vkRT->getFramebuffer(withResolve, withStencil, fSelfDependencyFlags, loadFromResolve);
+ if (!fb) {
+ return;
}
+ fFramebuffer = sk_ref_sp(fb);
+
+ SkASSERT(fFramebuffer);
+ const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
+ fFramebuffer->compatibleRenderPassHandle();
+ SkASSERT(rpHandle.isValid());
+
+ fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
+ vkColorOps,
+ vkResolveOps,
+ vkStencilOps);
+
if (!fCurrentRenderPass) {
return;
}
@@ -618,9 +581,7 @@
fCurrentRenderPass = nullptr;
return;
}
- const GrVkFramebuffer* framebuffer = vkRT->getFramebuffer(
- withResolve, withStencil, fSelfDependencyFlags, loadFromResolve);
- fCurrentSecondaryCommandBuffer->begin(fGpu, framebuffer, fCurrentRenderPass);
+ fCurrentSecondaryCommandBuffer->begin(fGpu, fFramebuffer.get(), fCurrentRenderPass);
}
VkClearValue vkClearColor;
@@ -867,9 +828,6 @@
SkASSERT(fGpu->isDeviceLost());
return;
}
- GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(fRenderTarget);
-
- GrVkImage* targetImage = target->colorAttachment();
VkRect2D bounds;
bounds.offset = { 0, 0 };
@@ -890,7 +848,7 @@
vkInfo.fSecondaryCommandBuffer = fCurrentSecondaryCommandBuffer->vkCommandBuffer();
vkInfo.fCompatibleRenderPass = fCurrentRenderPass->vkRenderPass();
SkAssertResult(fCurrentRenderPass->colorAttachmentIndex(&vkInfo.fColorAttachmentIndex));
- vkInfo.fFormat = targetImage->imageFormat();
+ vkInfo.fFormat = fFramebuffer->colorAttachment()->imageFormat();
vkInfo.fDrawBounds = &bounds;
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
vkInfo.fImage = targetImage->image();
diff --git a/src/gpu/vk/GrVkOpsRenderPass.h b/src/gpu/vk/GrVkOpsRenderPass.h
index 6a490dd..738e2bc 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.h
+++ b/src/gpu/vk/GrVkOpsRenderPass.h
@@ -16,6 +16,7 @@
#include "src/gpu/vk/GrVkPipelineState.h"
#include "src/gpu/vk/GrVkRenderPass.h"
+class GrVkFramebuffer;
class GrVkGpu;
class GrVkImage;
class GrVkRenderTarget;
@@ -32,13 +33,15 @@
void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override;
bool set(GrRenderTarget*,
- GrAttachment*,
+ sk_sp<GrVkFramebuffer>,
GrSurfaceOrigin,
const SkIRect& bounds,
const GrOpsRenderPass::LoadAndStoreInfo&,
const GrOpsRenderPass::StencilLoadAndStoreInfo&,
- const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
- GrXferBarrierFlags renderPassXferBarriers);
+ const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
+ GrVkRenderPass::SelfDependencyFlags selfDepFlags,
+ GrVkRenderPass::LoadFromResolve loadFromResolve,
+ const SkTArray<GrSurfaceProxy*, true>& sampledProxies);
void reset();
void submit();
@@ -50,10 +53,7 @@
private:
bool init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
const GrOpsRenderPass::LoadAndStoreInfo& resolveInfo,
- const GrOpsRenderPass::StencilLoadAndStoreInfo&,
- std::array<float, 4> clearColor,
- bool withResolve,
- bool withStencil);
+ const GrOpsRenderPass::StencilLoadAndStoreInfo&);
// Called instead of init when we are drawing to a render target that already wraps a secondary
// command buffer.
@@ -105,6 +105,7 @@
using SelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags;
+ sk_sp<GrVkFramebuffer> fFramebuffer;
std::unique_ptr<GrVkSecondaryCommandBuffer> fCurrentSecondaryCommandBuffer;
const GrVkRenderPass* fCurrentRenderPass;
SkIRect fCurrentPipelineBounds;
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp
index 082528a..870940a 100644
--- a/src/gpu/vk/GrVkRenderPass.cpp
+++ b/src/gpu/vk/GrVkRenderPass.cpp
@@ -395,15 +395,15 @@
return true;
}
-bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target,
+bool GrVkRenderPass::isCompatible(GrVkRenderTarget* target,
SelfDependencyFlags selfDepFlags,
LoadFromResolve loadFromResolve) const {
SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
AttachmentsDescriptor desc;
AttachmentFlags flags;
- target.getAttachmentsDescriptor(&desc, &flags, this->hasResolveAttachment(),
- this->hasStencilAttachment());
+ target->getAttachmentsDescriptor(&desc, &flags, this->hasResolveAttachment(),
+ this->hasStencilAttachment());
return this->isCompatible(desc, flags, selfDepFlags, loadFromResolve);
}
diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h
index 27b3759..63d99e4 100644
--- a/src/gpu/vk/GrVkRenderPass.h
+++ b/src/gpu/vk/GrVkRenderPass.h
@@ -125,7 +125,7 @@
// this object. Specifically this compares that the number of attachments, format of
// attachments, and sample counts are all the same. This function is used in the creation of
// basic RenderPasses that can be used when creating a VkFrameBuffer object.
- bool isCompatible(const GrVkRenderTarget& target,
+ bool isCompatible(GrVkRenderTarget* target,
SelfDependencyFlags selfDepFlags,
LoadFromResolve) const;
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index f6aeaf0..548832f 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -199,28 +199,45 @@
}
}
+GrVkAttachment* GrVkRenderTarget::dynamicMSAAAttachment() {
+ if (fDynamicMSAAAttachment) {
+ return fDynamicMSAAAttachment.get();
+ }
+ const GrVkAttachment* nonMSAAColorAttachment = this->colorAttachment();
+ SkASSERT(nonMSAAColorAttachment->numSamples() == 1);
+
+ GrVkGpu* gpu = this->getVkGpu();
+ auto rp = gpu->getContext()->priv().resourceProvider();
+
+ const GrBackendFormat& format = nonMSAAColorAttachment->backendFormat();
+
+ sk_sp<GrAttachment> msaaAttachment =
+ rp->makeMSAAAttachment(nonMSAAColorAttachment->dimensions(),
+ format,
+ gpu->caps()->internalMultisampleCount(format),
+ GrProtected(nonMSAAColorAttachment->isProtected()));
+ if (!msaaAttachment) {
+ return nullptr;
+ }
+ fDynamicMSAAAttachment =
+ sk_sp<GrVkAttachment>(static_cast<GrVkAttachment*>(msaaAttachment.release()));
+ return fDynamicMSAAAttachment.get();
+}
+
+GrVkAttachment* GrVkRenderTarget::msaaAttachment() {
+ return this->colorAttachment()->numSamples() == 1 ? this->dynamicMSAAAttachment()
+ : this->colorAttachment();
+}
+
bool GrVkRenderTarget::completeStencilAttachment() {
SkASSERT(!this->wrapsSecondaryCommandBuffer());
return true;
}
-std::unique_ptr<GrVkSecondaryCommandBuffer>
-GrVkRenderTarget::externalCommandBuffer() const {
- SkASSERT(this->wrapsSecondaryCommandBuffer());
- return fExternalFramebuffer->externalCommandBuffer();
+sk_sp<GrVkFramebuffer> GrVkRenderTarget::externalFramebuffer() const {
+ return fExternalFramebuffer;
}
-const GrVkRenderPass* GrVkRenderTarget::externalRenderPass() const {
- SkASSERT(this->wrapsSecondaryCommandBuffer());
- return fExternalFramebuffer->externalRenderPass();
-}
-
-void GrVkRenderTarget::returnExternalGrSecondaryCommandBuffer(
- std::unique_ptr<GrVkSecondaryCommandBuffer> cmdBuffer) {
- fExternalFramebuffer->returnExternalGrSecondaryCommandBuffer(std::move(cmdBuffer));
-}
-
-
GrVkResourceProvider::CompatibleRPHandle GrVkRenderTarget::compatibleRenderPassHandle(
bool withResolve,
bool withStencil,
@@ -285,7 +302,7 @@
SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedRenderPasses);
SkASSERT(!fCachedRenderPasses[cacheIndex]);
fCachedRenderPasses[cacheIndex] = rp.findCompatibleRenderPass(
- *this, &fCompatibleRPHandles[cacheIndex], withResolve, withStencil, selfDepFlags,
+ this, &fCompatibleRPHandles[cacheIndex], withResolve, withStencil, selfDepFlags,
loadFromResolve);
return fCachedRenderPasses[cacheIndex];
}
@@ -323,14 +340,16 @@
SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedRenderPasses);
GrVkAttachment* resolve = withResolve ? this->resolveAttachment() : nullptr;
+ GrVkAttachment* colorAttachment =
+ withResolve ? this->msaaAttachment() : this->colorAttachment();
// Stencil attachment view is stored in the base RT stencil attachment
GrVkAttachment* stencil =
withStencil ? static_cast<GrVkAttachment*>(this->getStencilAttachment())
: nullptr;
fCachedFramebuffers[cacheIndex] =
- GrVkFramebuffer::Create(gpu, this->width(), this->height(), renderPass,
- this->colorAttachment(), resolve, stencil, compatibleHandle);
+ GrVkFramebuffer::Create(gpu, this->dimensions(), renderPass,
+ colorAttachment, resolve, stencil, compatibleHandle);
return fCachedFramebuffers[cacheIndex];
}
@@ -338,10 +357,13 @@
void GrVkRenderTarget::getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc,
GrVkRenderPass::AttachmentFlags* attachmentFlags,
bool withResolve,
- bool withStencil) const {
+ bool withStencil) {
SkASSERT(!this->wrapsSecondaryCommandBuffer());
- desc->fColor.fFormat = fColorAttachment->imageFormat();
- desc->fColor.fSamples = fColorAttachment->numSamples();
+ const GrVkAttachment* colorAttachment =
+ withResolve ? this->msaaAttachment() : this->colorAttachment();
+
+ desc->fColor.fFormat = colorAttachment->imageFormat();
+ desc->fColor.fSamples = colorAttachment->numSamples();
*attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
uint32_t attachmentCount = 1;
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 73e2aab..056cbc7 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -59,7 +59,7 @@
}
const GrVkImageView* colorAttachmentView() const {
SkASSERT(!this->wrapsSecondaryCommandBuffer());
- return fColorAttachment->framebufferView();
+ return this->colorAttachment()->framebufferView();
}
GrVkAttachment* resolveAttachment() const {
@@ -98,9 +98,7 @@
LoadFromResolve);
bool wrapsSecondaryCommandBuffer() const { return SkToBool(fExternalFramebuffer); }
- std::unique_ptr<GrVkSecondaryCommandBuffer> externalCommandBuffer() const;
- void returnExternalGrSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer>);
- const GrVkRenderPass* externalRenderPass() const;
+ sk_sp<GrVkFramebuffer> externalFramebuffer() const;
bool canAttemptStencilAttachment() const override {
// We don't know the status of the stencil attachment for wrapped external secondary command
@@ -113,7 +111,7 @@
void getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc,
GrVkRenderPass::AttachmentFlags* flags,
bool withResolve,
- bool withStencil) const;
+ bool withStencil);
// Reconstruct the render target attachment information from the programInfo. This includes
// which attachments the render target will have (color, stencil) and the attachments' formats
@@ -157,6 +155,9 @@
GrVkGpu* getVkGpu() const;
+ GrVkAttachment* dynamicMSAAAttachment();
+ GrVkAttachment* msaaAttachment();
+
const GrVkRenderPass* createSimpleRenderPass(bool withResolve,
bool withStencil,
SelfDependencyFlags selfDepFlags,
@@ -182,6 +183,7 @@
sk_sp<GrVkAttachment> fColorAttachment;
sk_sp<GrVkAttachment> fResolveAttachment;
+ sk_sp<GrVkAttachment> fDynamicMSAAAttachment;
// We can have a renderpass with and without resolve attachment, stencil attachment,
// input attachment dependency, advanced blend dependency, and loading from resolve. All 5 of
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 0c9a3d4..25397e2 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -107,7 +107,7 @@
// only used for framebuffer creation. When we actually render we will create
// RenderPasses as needed that are compatible with the framebuffer.
const GrVkRenderPass*
-GrVkResourceProvider::findCompatibleRenderPass(const GrVkRenderTarget& target,
+GrVkResourceProvider::findCompatibleRenderPass(GrVkRenderTarget* target,
CompatibleRPHandle* compatibleHandle,
bool withResolve,
bool withStencil,
@@ -117,7 +117,7 @@
// target has (color, stencil) and the attachments format and sample count.
GrVkRenderPass::AttachmentFlags attachmentFlags;
GrVkRenderPass::AttachmentsDescriptor attachmentsDesc;
- target.getAttachmentsDescriptor(&attachmentsDesc, &attachmentFlags, withResolve, withStencil);
+ target->getAttachmentsDescriptor(&attachmentsDesc, &attachmentFlags, withResolve, withStencil);
return this->findCompatibleRenderPass(&attachmentsDesc, attachmentFlags, selfDepFlags,
loadFromResolve, compatibleHandle);
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 3e5c527..1e8702f 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -68,7 +68,7 @@
// and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle. If this is
// non null it will be set to a handle that can be used in the furutre to quickly return a
// compatible GrVkRenderPasses without the need inspecting a GrVkRenderTarget.
- const GrVkRenderPass* findCompatibleRenderPass(const GrVkRenderTarget& target,
+ const GrVkRenderPass* findCompatibleRenderPass(GrVkRenderTarget* target,
CompatibleRPHandle* compatibleHandle,
bool withResolve,
bool withStencil,