Add initial support for creating a vulkan secondary command buffer drawing context.
This sets up the context and adds support for creating RTContexts, RTProxies, RTs,
and GrVkRenderPass's that wrap the external secondary command buffer.
Bug: skia:
Change-Id: I80ebbb690a5fe464f775c5fcad651dfe2a150418
Reviewed-on: https://skia-review.googlesource.com/c/178926
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index ee7fa89..0d42653 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -235,6 +235,7 @@
SkSurfaceCharacterization::Textureable(true),
SkSurfaceCharacterization::MipMapped(isMipMapped),
SkSurfaceCharacterization::UsesGLFBO0(willUseGLFBO0),
+ SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
surfaceProps);
}
@@ -997,6 +998,20 @@
props);
}
+sk_sp<GrRenderTargetContext> GrContextPriv::makeVulkanSecondaryCBRenderTargetContext(
+ const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo, const SkSurfaceProps* props) {
+ ASSERT_SINGLE_OWNER_PRIV
+ sk_sp<GrSurfaceProxy> proxy(
+ this->proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo));
+ if (!proxy) {
+ return nullptr;
+ }
+
+ return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+ imageInfo.refColorSpace(),
+ props);
+}
+
void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
}
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index f62979a..8480deb 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -77,6 +77,9 @@
sk_sp<SkColorSpace> colorSpace,
const SkSurfaceProps* = nullptr);
+ sk_sp<GrRenderTargetContext> makeVulkanSecondaryCBRenderTargetContext(
+ const SkImageInfo&, const GrVkDrawableInfo&, const SkSurfaceProps* = nullptr);
+
bool disableGpuYUVConversion() const { return fContext->fDisableGpuYUVConversion; }
bool sharpenMipmappedTextures() const { return fContext->fSharpenMipmappedTextures; }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index ae7dac6..cd93f8d 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -200,6 +200,17 @@
return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt);
}
+sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
+ const GrVkDrawableInfo& vkInfo) {
+ return this->onWrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo);
+}
+
+sk_sp<GrRenderTarget> GrGpu::onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
+ const GrVkDrawableInfo& vkInfo) {
+ // This is only supported on Vulkan so we default to returning nullptr here
+ return nullptr;
+}
+
GrBuffer* GrGpu::createBuffer(size_t size, GrBufferType intendedType,
GrAccessPattern accessPattern, const void* data) {
this->handleDirtyContext();
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index c4b6f76..850934e 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -125,6 +125,12 @@
int sampleCnt);
/**
+ * Implements GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget
+ */
+ sk_sp<GrRenderTarget> wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
+ const GrVkDrawableInfo&);
+
+ /**
* Creates a buffer in GPU memory. For a client-side buffer use GrBuffer::CreateCPUBacked.
*
* @param size size of buffer to create.
@@ -457,6 +463,9 @@
virtual sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTarget&) = 0;
virtual sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTexture&,
int sampleCnt) = 0;
+ virtual sk_sp<GrRenderTarget> onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
+ const GrVkDrawableInfo&);
+
virtual GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern,
const void* data) = 0;
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 0e9616a..0a45d60 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -515,12 +515,41 @@
}
SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
SkASSERT(!rt->getUniqueKey().isValid());
- // Make sure we match how we created the proxy with SkBudgeted::kNo
+ // This proxy should be unbudgeted because we're just wrapping an external resource
SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted());
return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
}
+sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget(
+ const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
+ if (this->isAbandoned()) {
+ return nullptr;
+ }
+
+ // This is only supported on a direct GrContext.
+ if (!fResourceProvider) {
+ return nullptr;
+ }
+
+ sk_sp<GrRenderTarget> rt = fResourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
+ vkInfo);
+
+ if (!rt) {
+ return nullptr;
+ }
+ SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
+ SkASSERT(!rt->getUniqueKey().isValid());
+ // This proxy should be unbudgeted because we're just wrapping an external resource
+ SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted());
+
+ // All Vulkan surfaces uses top left origins.
+ return sk_sp<GrRenderTargetProxy>(
+ new GrRenderTargetProxy(std::move(rt),
+ kTopLeft_GrSurfaceOrigin,
+ GrRenderTargetProxy::WrapsVkSecondaryCB::kYes));
+}
+
sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
const GrBackendFormat& format,
const GrSurfaceDesc& desc,
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index 8cdaab5..dd5cfb0 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -131,6 +131,9 @@
GrSurfaceOrigin origin,
int sampleCnt);
+ sk_sp<GrRenderTargetProxy> wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
+ const GrVkDrawableInfo&);
+
using LazyInstantiateCallback = std::function<sk_sp<GrSurface>(GrResourceProvider*)>;
enum class Renderable : bool {
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 4c73746..f66acc5 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -377,6 +377,7 @@
int numStencilSamples() const { return fRenderTargetProxy->numStencilSamples(); }
const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; }
GrSurfaceOrigin origin() const { return fRenderTargetProxy->origin(); }
+ bool wrapsVkSecondaryCB() const { return fRenderTargetProxy->wrapsVkSecondaryCB(); }
GrMipMapped mipMapped() const;
bool wasAbandoned() const;
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index 3e3e245..ee32309 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -25,7 +25,8 @@
GrInternalSurfaceFlags surfaceFlags)
: INHERITED(format, desc, origin, fit, budgeted, surfaceFlags)
, fSampleCnt(desc.fSampleCnt)
- , fNeedsStencil(false) {
+ , fNeedsStencil(false)
+ , fWrapsVkSecondaryCB(WrapsVkSecondaryCB::kNo) {
// Since we know the newly created render target will be internal, we are able to precompute
// what the flags will ultimately end up being.
if (caps.usesMixedSamples() && fSampleCnt > 1) {
@@ -42,15 +43,18 @@
: INHERITED(std::move(callback), lazyType, format, desc, origin, fit, budgeted,
surfaceFlags)
, fSampleCnt(desc.fSampleCnt)
- , fNeedsStencil(false) {
+ , fNeedsStencil(false)
+ , fWrapsVkSecondaryCB(WrapsVkSecondaryCB::kNo) {
SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags));
}
// Wrapped version
-GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
+GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin,
+ WrapsVkSecondaryCB wrapsVkSecondaryCB)
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
, fSampleCnt(fTarget->asRenderTarget()->numStencilSamples())
- , fNeedsStencil(false) {
+ , fNeedsStencil(false)
+ , fWrapsVkSecondaryCB(wrapsVkSecondaryCB) {
}
int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const {
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 1193246..6e821db 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -252,6 +252,14 @@
return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
}
+sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
+ const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
+ ASSERT_SINGLE_OWNER
+ return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
+ vkInfo);
+
+}
+
void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
GrGpuResource* resource) {
ASSERT_SINGLE_OWNER
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index c86136f..fe1bdd3 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -25,6 +25,7 @@
class GrSingleOwner;
class GrStencilAttachment;
class GrTexture;
+struct GrVkDrawableInfo;
class GrStyle;
class SkDescriptor;
@@ -131,6 +132,9 @@
*/
sk_sp<GrRenderTarget> wrapBackendRenderTarget(const GrBackendRenderTarget&);
+ sk_sp<GrRenderTarget> wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
+ const GrVkDrawableInfo&);
+
static const uint32_t kMinScratchTextureSize;
/**
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 86e1f04..7d71d22 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -990,6 +990,36 @@
return GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, imageInfo, std::move(layout));
}
+sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget(
+ const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
+ int maxSize = this->caps()->maxTextureSize();
+ if (imageInfo.width() > maxSize || imageInfo.height() > maxSize) {
+ return nullptr;
+ }
+
+ GrBackendFormat backendFormat = GrBackendFormat::MakeVk(vkInfo.fFormat);
+ if (!backendFormat.isValid()) {
+ return nullptr;
+ }
+ GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendFormat,
+ imageInfo.colorType());
+ if (config == kUnknown_GrPixelConfig) {
+ return nullptr;
+ }
+
+ GrSurfaceDesc desc;
+ desc.fFlags = kRenderTarget_GrSurfaceFlag;
+ desc.fWidth = imageInfo.width();
+ desc.fHeight = imageInfo.height();
+ desc.fConfig = config;
+ desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(1, config);
+ if (!desc.fSampleCnt) {
+ return nullptr;
+ }
+
+ return GrVkRenderTarget::MakeSecondaryCBRenderTarget(this, desc, vkInfo);
+}
+
bool GrVkGpu::onRegenerateMipMapLevels(GrTexture* tex) {
auto* vkTex = static_cast<GrVkTexture*>(tex);
// don't do anything for linearly tiled textures (can't have mipmaps)
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 3aae807..22cf45e 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -187,6 +187,9 @@
sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTexture&,
int sampleCnt) override;
+ sk_sp<GrRenderTarget> onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo&,
+ const GrVkDrawableInfo&) override;
+
GrBuffer* onCreateBuffer(size_t size, GrBufferType type, GrAccessPattern,
const void* data) override;
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index 0729531..ead8d8d 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -209,10 +209,6 @@
GrVkMemory::FreeImageMemory(gpu, isLinear, info->fAlloc);
}
-void GrVkImage::setNewResource(VkImage image, const GrVkAlloc& alloc, VkImageTiling tiling) {
- fResource = new Resource(image, alloc, tiling);
-}
-
GrVkImage::~GrVkImage() {
// should have been released or abandoned first
SkASSERT(!fResource);
@@ -238,6 +234,7 @@
}
void GrVkImage::setResourceRelease(sk_sp<GrReleaseProcHelper> releaseHelper) {
+ SkASSERT(fResource);
// Forward the release proc on to GrVkImage::Resource
fResource->setRelease(std::move(releaseHelper));
}
diff --git a/src/gpu/vk/GrVkImage.h b/src/gpu/vk/GrVkImage.h
index 91ae488..0ce223c 100644
--- a/src/gpu/vk/GrVkImage.h
+++ b/src/gpu/vk/GrVkImage.h
@@ -25,13 +25,15 @@
public:
GrVkImage(const GrVkImageInfo& info, sk_sp<GrVkImageLayout> layout,
- GrBackendObjectOwnership ownership)
+ GrBackendObjectOwnership ownership, bool forSecondaryCB = false)
: fInfo(info)
, fInitialQueueFamily(info.fCurrentQueueFamily)
, fLayout(std::move(layout))
, fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
SkASSERT(fLayout->getImageLayout() == fInfo.fImageLayout);
- if (fIsBorrowed) {
+ if (forSecondaryCB) {
+ fResource = nullptr;
+ } else if (fIsBorrowed) {
fResource = new BorrowedResource(info.fImage, info.fAlloc, info.fImageTiling);
} else {
fResource = new Resource(info.fImage, info.fAlloc, info.fImageTiling);
@@ -39,18 +41,37 @@
}
virtual ~GrVkImage();
- VkImage image() const { return fInfo.fImage; }
- const GrVkAlloc& alloc() const { return fInfo.fAlloc; }
+ VkImage image() const {
+ // Should only be called when we have a real fResource object, i.e. never when being used as
+ // a RT in an external secondary command buffer.
+ SkASSERT(fResource);
+ return fInfo.fImage;
+ }
+ const GrVkAlloc& alloc() const {
+ // Should only be called when we have a real fResource object, i.e. never when being used as
+ // a RT in an external secondary command buffer.
+ SkASSERT(fResource);
+ return fInfo.fAlloc;
+ }
VkFormat imageFormat() const { return fInfo.fFormat; }
GrBackendFormat getBackendFormat() const {
return GrBackendFormat::MakeVk(this->imageFormat());
}
uint32_t mipLevels() const { return fInfo.fLevelCount; }
const GrVkYcbcrConversionInfo& ycbcrConversionInfo() const {
+ // Should only be called when we have a real fResource object, i.e. never when being used as
+ // a RT in an external secondary command buffer.
+ SkASSERT(fResource);
return fInfo.fYcbcrConversionInfo;
}
- const Resource* resource() const { return fResource; }
+ const Resource* resource() const {
+ SkASSERT(fResource);
+ return fResource;
+ }
bool isLinearTiled() const {
+ // Should only be called when we have a real fResource object, i.e. never when being used as
+ // a RT in an external secondary command buffer.
+ SkASSERT(fResource);
return SkToBool(VK_IMAGE_TILING_LINEAR == fInfo.fImageTiling);
}
bool isBorrowed() const { return fIsBorrowed; }
@@ -72,6 +93,9 @@
// This is only used for mip map generation where we are manually changing the layouts as we
// blit each layer, and then at the end need to update our tracking.
void updateImageLayout(VkImageLayout newLayout) {
+ // Should only be called when we have a real fResource object, i.e. never when being used as
+ // a RT in an external secondary command buffer.
+ SkASSERT(fResource);
fLayout->setImageLayout(newLayout);
}
@@ -116,8 +140,6 @@
void releaseImage(GrVkGpu* gpu);
void abandonImage();
- void setNewResource(VkImage image, const GrVkAlloc& alloc, VkImageTiling tiling);
-
GrVkImageInfo fInfo;
uint32_t fInitialQueueFamily;
sk_sp<GrVkImageLayout> fLayout;
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp
index 682244c..7077528 100644
--- a/src/gpu/vk/GrVkRenderPass.cpp
+++ b/src/gpu/vk/GrVkRenderPass.cpp
@@ -164,14 +164,15 @@
}
void GrVkRenderPass::freeGPUData(GrVkGpu* gpu) const {
- GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr));
+ if (!(fAttachmentFlags & kExternal_AttachmentFlag)) {
+ GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr));
+ }
}
-// Works under the assumption that color attachment will always be the first attachment in our
-// attachment array if it exists.
bool GrVkRenderPass::colorAttachmentIndex(uint32_t* index) const {
- *index = 0;
- if (fAttachmentFlags & kColor_AttachmentFlag) {
+ *index = fColorAttachmentIndex;
+ if ((fAttachmentFlags & kColor_AttachmentFlag) ||
+ (fAttachmentFlags & kExternal_AttachmentFlag)) {
return true;
}
return false;
@@ -192,6 +193,7 @@
bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc,
const AttachmentFlags& flags) const {
+ SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
if (flags != fAttachmentFlags) {
return false;
}
@@ -211,6 +213,7 @@
}
bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
+ SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
AttachmentsDescriptor desc;
AttachmentFlags flags;
target.getAttachmentsDescriptor(&desc, &flags);
@@ -219,11 +222,18 @@
}
bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
+ SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
}
+bool GrVkRenderPass::isCompatibleExternalRP(VkRenderPass renderPass) const {
+ SkASSERT(fAttachmentFlags & kExternal_AttachmentFlag);
+ return fRenderPass == renderPass;
+}
+
bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps,
const LoadStoreOps& stencilOps) const {
+ SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
if (fAttachmentFlags & kColor_AttachmentFlag) {
if (fAttachmentsDescriptor.fColor.fLoadStoreOps != colorOps) {
return false;
@@ -247,4 +257,10 @@
b->add32(fAttachmentsDescriptor.fStencil.fFormat);
b->add32(fAttachmentsDescriptor.fStencil.fSamples);
}
+ if (fAttachmentFlags & kExternal_AttachmentFlag) {
+ SkASSERT(!(fAttachmentFlags & ~kExternal_AttachmentFlag));
+ uint64_t handle = (uint64_t)fRenderPass;
+ b->add32((uint32_t)handle);
+ b->add32((uint32_t)(handle>>32));
+ }
}
diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h
index ce66811..b6e4497 100644
--- a/src/gpu/vk/GrVkRenderPass.h
+++ b/src/gpu/vk/GrVkRenderPass.h
@@ -20,6 +20,15 @@
public:
GrVkRenderPass() : INHERITED(), fRenderPass(VK_NULL_HANDLE), fClearValueCount(0) {}
+ // Used when importing an external render pass. In this case we have to explicitly be told the
+ // color attachment index
+ explicit GrVkRenderPass(VkRenderPass renderPass, uint32_t colorAttachmentIndex)
+ : INHERITED()
+ , fRenderPass(renderPass)
+ , fAttachmentFlags(kExternal_AttachmentFlag)
+ , fClearValueCount(0)
+ , fColorAttachmentIndex(colorAttachmentIndex) {}
+
struct LoadStoreOps {
VkAttachmentLoadOp fLoadOp;
VkAttachmentStoreOp fStoreOp;
@@ -78,6 +87,11 @@
enum AttachmentFlags {
kColor_AttachmentFlag = 0x1,
kStencil_AttachmentFlag = 0x2,
+ // The external attachment flag signals that this render pass is imported from an external
+ // client. Since we don't know every attachment on the render pass we don't set any of the
+ // specific attachment flags when using external. However, the external render pass must
+ // at least have a color attachment.
+ kExternal_AttachmentFlag = 0x4,
};
GR_DECL_BITFIELD_OPS_FRIENDS(AttachmentFlags);
@@ -95,6 +109,8 @@
bool isCompatible(const GrVkRenderPass& renderPass) const;
+ bool isCompatibleExternalRP(VkRenderPass) const;
+
bool equalLoadStoreOps(const LoadStoreOps& colorOps,
const LoadStoreOps& stencilOps) const;
@@ -131,6 +147,8 @@
AttachmentsDescriptor fAttachmentsDescriptor;
VkExtent2D fGranularity;
uint32_t fClearValueCount;
+ // For internally created render passes we assume the color attachment index is always 0.
+ uint32_t fColorAttachmentIndex = 0;
typedef GrVkResource INHERITED;
};
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index d1393f9..fcbc470 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -30,15 +30,16 @@
sk_sp<GrVkImageLayout> msaaLayout,
const GrVkImageView* colorAttachmentView,
const GrVkImageView* resolveAttachmentView)
- : GrSurface(gpu, desc)
- , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
- // for the moment we only support 1:1 color to stencil
- , GrRenderTarget(gpu, desc)
- , fColorAttachmentView(colorAttachmentView)
- , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout), GrBackendObjectOwnership::kOwned))
- , fResolveAttachmentView(resolveAttachmentView)
- , fFramebuffer(nullptr)
- , fCachedSimpleRenderPass(nullptr) {
+ : GrSurface(gpu, desc)
+ , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
+ // for the moment we only support 1:1 color to stencil
+ , GrRenderTarget(gpu, desc)
+ , fColorAttachmentView(colorAttachmentView)
+ , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout),
+ GrBackendObjectOwnership::kOwned))
+ , fResolveAttachmentView(resolveAttachmentView)
+ , fFramebuffer(nullptr)
+ , fCachedSimpleRenderPass(nullptr) {
SkASSERT(desc.fSampleCnt > 1);
this->createFramebuffer(gpu);
this->registerWithCacheWrapped();
@@ -55,15 +56,16 @@
const GrVkImageView* colorAttachmentView,
const GrVkImageView* resolveAttachmentView,
GrBackendObjectOwnership ownership)
- : GrSurface(gpu, desc)
- , GrVkImage(info, std::move(layout), ownership)
- // for the moment we only support 1:1 color to stencil
- , GrRenderTarget(gpu, desc)
- , fColorAttachmentView(colorAttachmentView)
- , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout), GrBackendObjectOwnership::kOwned))
- , fResolveAttachmentView(resolveAttachmentView)
- , fFramebuffer(nullptr)
- , fCachedSimpleRenderPass(nullptr) {
+ : GrSurface(gpu, desc)
+ , GrVkImage(info, std::move(layout), ownership)
+ // for the moment we only support 1:1 color to stencil
+ , GrRenderTarget(gpu, desc)
+ , fColorAttachmentView(colorAttachmentView)
+ , fMSAAImage(new GrVkImage(msaaInfo, std::move(msaaLayout),
+ GrBackendObjectOwnership::kOwned))
+ , fResolveAttachmentView(resolveAttachmentView)
+ , fFramebuffer(nullptr)
+ , fCachedSimpleRenderPass(nullptr) {
SkASSERT(desc.fSampleCnt > 1);
this->createFramebuffer(gpu);
}
@@ -75,14 +77,14 @@
const GrVkImageInfo& info,
sk_sp<GrVkImageLayout> layout,
const GrVkImageView* colorAttachmentView)
- : GrSurface(gpu, desc)
- , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
- , GrRenderTarget(gpu, desc)
- , fColorAttachmentView(colorAttachmentView)
- , fMSAAImage(nullptr)
- , fResolveAttachmentView(nullptr)
- , fFramebuffer(nullptr)
- , fCachedSimpleRenderPass(nullptr) {
+ : GrSurface(gpu, desc)
+ , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed)
+ , GrRenderTarget(gpu, desc)
+ , fColorAttachmentView(colorAttachmentView)
+ , fMSAAImage(nullptr)
+ , fResolveAttachmentView(nullptr)
+ , fFramebuffer(nullptr)
+ , fCachedSimpleRenderPass(nullptr) {
SkASSERT(1 == desc.fSampleCnt);
this->createFramebuffer(gpu);
this->registerWithCacheWrapped();
@@ -96,23 +98,39 @@
sk_sp<GrVkImageLayout> layout,
const GrVkImageView* colorAttachmentView,
GrBackendObjectOwnership ownership)
- : GrSurface(gpu, desc)
- , GrVkImage(info, std::move(layout), ownership)
- , GrRenderTarget(gpu, desc)
- , fColorAttachmentView(colorAttachmentView)
- , fMSAAImage(nullptr)
- , fResolveAttachmentView(nullptr)
- , fFramebuffer(nullptr)
- , fCachedSimpleRenderPass(nullptr) {
+ : GrSurface(gpu, desc)
+ , GrVkImage(info, std::move(layout), ownership)
+ , GrRenderTarget(gpu, desc)
+ , fColorAttachmentView(colorAttachmentView)
+ , fMSAAImage(nullptr)
+ , fResolveAttachmentView(nullptr)
+ , fFramebuffer(nullptr)
+ , fCachedSimpleRenderPass(nullptr) {
SkASSERT(1 == desc.fSampleCnt);
this->createFramebuffer(gpu);
}
-sk_sp<GrVkRenderTarget>
-GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
- const GrSurfaceDesc& desc,
- const GrVkImageInfo& info,
- sk_sp<GrVkImageLayout> layout) {
+GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
+ const GrSurfaceDesc& desc,
+ const GrVkImageInfo& info,
+ sk_sp<GrVkImageLayout> layout,
+ const GrVkRenderPass* renderPass,
+ VkCommandBuffer secondaryCommandBuffer)
+ : GrSurface(gpu, desc)
+ , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed, true)
+ , GrRenderTarget(gpu, desc)
+ , fColorAttachmentView(nullptr)
+ , fMSAAImage(nullptr)
+ , fResolveAttachmentView(nullptr)
+ , fFramebuffer(nullptr)
+ , fCachedSimpleRenderPass(renderPass)
+ , fSecondaryCommandBuffer(secondaryCommandBuffer) {
+ this->registerWithCacheWrapped();
+}
+
+sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
+ GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkImageInfo& info,
+ sk_sp<GrVkImageLayout> layout) {
SkASSERT(VK_NULL_HANDLE != info.fImage);
SkASSERT(1 == info.fLevelCount);
@@ -184,12 +202,37 @@
return sk_sp<GrVkRenderTarget>(vkRT);
}
+sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
+ GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkDrawableInfo& vkInfo) {
+ // We only set the few properties of the GrVkImageInfo that we know like layout and format. The
+ // others we keep at the default "null" values.
+ GrVkImageInfo info;
+ info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ info.fFormat = vkInfo.fFormat;
+
+ sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
+
+ const GrVkRenderPass* rp =
+ gpu->resourceProvider().findCompatibleExternalRenderPass(vkInfo.fCompatibleRenderPass,
+ vkInfo.fColorAttachmentIndex);
+ if (!rp) {
+ return nullptr;
+ }
+
+ GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, desc, info, std::move(layout), rp,
+ vkInfo.fSecondaryCommandBuffer);
+
+ return sk_sp<GrVkRenderTarget>(vkRT);
+}
+
bool GrVkRenderTarget::completeStencilAttachment() {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
this->createFramebuffer(this->getVkGpu());
return true;
}
void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
if (fFramebuffer) {
fFramebuffer->unref(gpu);
}
@@ -213,6 +256,7 @@
void GrVkRenderTarget::getAttachmentsDescriptor(
GrVkRenderPass::AttachmentsDescriptor* desc,
GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
VkFormat colorFormat;
GrPixelConfigToVkFormat(this->config(), &colorFormat);
desc->fColor.fFormat = colorFormat;
@@ -317,11 +361,13 @@
GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
return GrBackendRenderTarget(this->width(), this->height(), this->numColorSamples(),
fInfo, this->grVkImageLayout());
}
const GrVkResource* GrVkRenderTarget::stencilImageResource() const {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
if (stencil) {
const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
@@ -332,6 +378,7 @@
}
const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
if (stencil) {
const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
@@ -341,7 +388,6 @@
return nullptr;
}
-
GrVkGpu* GrVkRenderTarget::getVkGpu() const {
SkASSERT(!this->wasDestroyed());
return static_cast<GrVkGpu*>(this->getGpu());
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index f936a19..dc695fc 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -36,6 +36,9 @@
const GrVkImageInfo&,
sk_sp<GrVkImageLayout>);
+ static sk_sp<GrVkRenderTarget> MakeSecondaryCBRenderTarget(GrVkGpu*, const GrSurfaceDesc&,
+ const GrVkDrawableInfo& vkInfo);
+
~GrVkRenderTarget() override;
GrBackendFormat backendFormat() const override { return this->getBackendFormat(); }
@@ -55,8 +58,16 @@
const GrVkRenderPass* simpleRenderPass() const { return fCachedSimpleRenderPass; }
GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle() const {
+ SkASSERT(!this->wrapsSecondaryCommandBuffer());
return fCompatibleRPHandle;
}
+ const GrVkRenderPass* externalRenderPass() const {
+ SkASSERT(this->wrapsSecondaryCommandBuffer());
+ // We use the cached simple render pass to hold the external render pass.
+ return fCachedSimpleRenderPass;
+ }
+
+ bool wrapsSecondaryCommandBuffer() const { return fSecondaryCommandBuffer != VK_NULL_HANDLE; }
// override of GrRenderTarget
ResolveType getResolveType() const override {
@@ -67,7 +78,9 @@
}
bool canAttemptStencilAttachment() const override {
- return true;
+ // We don't know the status of the stencil attachment for wrapped external secondary command
+ // buffers so we just assume we don't have one.
+ return !this->wrapsSecondaryCommandBuffer();
}
GrBackendRenderTarget getBackendRenderTarget() const override;
@@ -133,6 +146,14 @@
sk_sp<GrVkImageLayout> layout,
const GrVkImageView* colorAttachmentView);
+
+ GrVkRenderTarget(GrVkGpu* gpu,
+ const GrSurfaceDesc& desc,
+ const GrVkImageInfo& info,
+ sk_sp<GrVkImageLayout> layout,
+ const GrVkRenderPass* renderPass,
+ VkCommandBuffer secondaryCommandBuffer);
+
bool completeStencilAttachment() override;
void releaseInternalObjects();
@@ -145,6 +166,11 @@
const GrVkRenderPass* fCachedSimpleRenderPass;
// This is a handle to be used to quickly get compatible GrVkRenderPasses for this render target
GrVkResourceProvider::CompatibleRPHandle fCompatibleRPHandle;
+
+ // Handle to an external secondary command buffer which this GrVkRenderTarget represents. If
+ // this is not VK_NULL_HANDLE then the GrVkRenderTarget does not have a real VkImage backing it,
+ // and is limited in what it can be used for.
+ VkCommandBuffer fSecondaryCommandBuffer = VK_NULL_HANDLE;
};
#endif
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index 99b4d12..060bc87 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -31,6 +31,7 @@
GrVkResourceProvider::~GrVkResourceProvider() {
SkASSERT(0 == fRenderPassArray.count());
+ SkASSERT(0 == fExternalRenderPasses.count());
SkASSERT(VK_NULL_HANDLE == fPipelineCache);
delete fPipelineStateCache;
}
@@ -134,6 +135,26 @@
return renderPass;
}
+const GrVkRenderPass* GrVkResourceProvider::findCompatibleExternalRenderPass(
+ VkRenderPass renderPass, uint32_t colorAttachmentIndex) {
+ for (int i = 0; i < fExternalRenderPasses.count(); ++i) {
+ if (fExternalRenderPasses[i]->isCompatibleExternalRP(renderPass)) {
+ fExternalRenderPasses[i]->ref();
+#ifdef SK_DEBUG
+ uint32_t cachedColorIndex;
+ SkASSERT(fExternalRenderPasses[i]->colorAttachmentIndex(&cachedColorIndex));
+ SkASSERT(cachedColorIndex == colorAttachmentIndex);
+#endif
+ return fExternalRenderPasses[i];
+ }
+ }
+
+ const GrVkRenderPass* newRenderPass = new GrVkRenderPass(renderPass, colorAttachmentIndex);
+ fExternalRenderPasses.push_back(newRenderPass);
+ newRenderPass->ref();
+ return newRenderPass;
+}
+
const GrVkRenderPass* GrVkResourceProvider::findRenderPass(
const GrVkRenderTarget& target,
const GrVkRenderPass::LoadStoreOps& colorOps,
@@ -346,6 +367,11 @@
}
fRenderPassArray.reset();
+ for (int i = 0; i < fExternalRenderPasses.count(); ++i) {
+ fExternalRenderPasses[i]->unref(fGpu);
+ }
+ fExternalRenderPasses.reset();
+
// Iterate through all store GrVkSamplers and unref them before resetting the hash.
SkTDynamicHash<GrVkSampler, GrVkSampler::Key>::Iter iter(&fSamplers);
for (; !iter.done(); ++iter) {
@@ -414,6 +440,11 @@
}
fRenderPassArray.reset();
+ for (int i = 0; i < fExternalRenderPasses.count(); ++i) {
+ fExternalRenderPasses[i]->unrefAndAbandon();
+ }
+ fExternalRenderPasses.reset();
+
// Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash.
SkTDynamicHash<GrVkSampler, GrVkSampler::Key>::Iter iter(&fSamplers);
for (; !iter.done(); ++iter) {
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index 4b0e00a..2eac2b2 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -69,6 +69,9 @@
// findCompatibleRenderPass(GrVkRenderTarget&, CompatibleRPHandle*).
const GrVkRenderPass* findCompatibleRenderPass(const CompatibleRPHandle& compatibleHandle);
+ const GrVkRenderPass* findCompatibleExternalRenderPass(VkRenderPass,
+ uint32_t colorAttachmentIndex);
+
// Finds or creates a render pass that matches the target and LoadStoreOps, increments the
// refcount, 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
@@ -252,6 +255,8 @@
SkSTArray<4, CompatibleRenderPassSet> fRenderPassArray;
+ SkTArray<const GrVkRenderPass*> fExternalRenderPasses;
+
// Array of command pools that we are waiting on
SkSTArray<4, GrVkCommandPool*, true> fActiveCommandPools;
diff --git a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
new file mode 100644
index 0000000..a7e5e3f
--- /dev/null
+++ b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "vk/GrVkSecondaryCBDrawContext.h"
+
+#include "GrContext.h"
+#include "GrContextPriv.h"
+#include "GrRenderTargetContext.h"
+#include "SkGpuDevice.h"
+#include "SkImageInfo.h"
+#include "SkSurfaceProps.h"
+#include "vk/GrVkTypes.h"
+
+sk_sp<GrVkSecondaryCBDrawContext> GrVkSecondaryCBDrawContext::Make(GrContext* ctx,
+ const SkImageInfo& imageInfo,
+ const GrVkDrawableInfo& vkInfo,
+ const SkSurfaceProps* props) {
+ if (!ctx) {
+ return nullptr;
+ }
+
+ if (ctx->contextPriv().getBackend() != GrBackendApi::kVulkan) {
+ return nullptr;
+ }
+
+ sk_sp<GrRenderTargetContext> rtc(
+ ctx->contextPriv().makeVulkanSecondaryCBRenderTargetContext(imageInfo, vkInfo, props));
+
+ int width = rtc->width();
+ int height = rtc->height();
+
+ sk_sp<SkGpuDevice> device(SkGpuDevice::Make(ctx, std::move(rtc), width, height,
+ SkGpuDevice::kUninit_InitContents));
+ if (!device) {
+ return nullptr;
+ }
+
+ return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device)));
+}
+
+GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice> device)
+ : fDevice(device) {}
+
+GrVkSecondaryCBDrawContext::~GrVkSecondaryCBDrawContext() {
+ SkASSERT(!fDevice);
+ SkASSERT(!fCachedCanvas.get());
+}
+
+SkCanvas* GrVkSecondaryCBDrawContext::getCanvas() {
+ if (!fCachedCanvas) {
+ fCachedCanvas = std::unique_ptr<SkCanvas>(new SkCanvas(fDevice));
+ }
+ return fCachedCanvas.get();
+}
+
+void GrVkSecondaryCBDrawContext::flush() {
+ fDevice->flush();
+}
+
+void GrVkSecondaryCBDrawContext::releaseResources() {
+ fCachedCanvas.reset();
+ fDevice.reset();
+}
+