Implement blit image for copySurface in Vulkan
Also allows CopyImage to handle GrRenderTargets which are not textures. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1852413002 Review URL: https://codereview.chromium.org/1852413002
This commit is contained in:
parent
74cb44dee5
commit
17b8925514
@ -253,6 +253,28 @@ void GrVkCommandBuffer::copyImage(const GrVkGpu* gpu,
|
|||||||
copyRegions));
|
copyRegions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrVkCommandBuffer::blitImage(const GrVkGpu* gpu,
|
||||||
|
GrVkImage* srcImage,
|
||||||
|
VkImageLayout srcLayout,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
VkImageLayout dstLayout,
|
||||||
|
uint32_t blitRegionCount,
|
||||||
|
const VkImageBlit* blitRegions,
|
||||||
|
VkFilter filter) {
|
||||||
|
SkASSERT(fIsActive);
|
||||||
|
SkASSERT(!fActiveRenderPass);
|
||||||
|
this->addResource(srcImage->resource());
|
||||||
|
this->addResource(dstImage->resource());
|
||||||
|
GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer,
|
||||||
|
srcImage->textureImage(),
|
||||||
|
srcLayout,
|
||||||
|
dstImage->textureImage(),
|
||||||
|
dstLayout,
|
||||||
|
blitRegionCount,
|
||||||
|
blitRegions,
|
||||||
|
filter));
|
||||||
|
}
|
||||||
|
|
||||||
void GrVkCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu,
|
void GrVkCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu,
|
||||||
GrVkImage* srcImage,
|
GrVkImage* srcImage,
|
||||||
VkImageLayout srcLayout,
|
VkImageLayout srcLayout,
|
||||||
|
@ -124,6 +124,15 @@ public:
|
|||||||
uint32_t copyRegionCount,
|
uint32_t copyRegionCount,
|
||||||
const VkImageCopy* copyRegions);
|
const VkImageCopy* copyRegions);
|
||||||
|
|
||||||
|
void blitImage(const GrVkGpu* gpu,
|
||||||
|
GrVkImage* srcImage,
|
||||||
|
VkImageLayout srcLayout,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
VkImageLayout dstLayout,
|
||||||
|
uint32_t blitRegionCount,
|
||||||
|
const VkImageBlit* blitRegions,
|
||||||
|
VkFilter filter);
|
||||||
|
|
||||||
void copyImageToBuffer(const GrVkGpu* gpu,
|
void copyImageToBuffer(const GrVkGpu* gpu,
|
||||||
GrVkImage* srcImage,
|
GrVkImage* srcImage,
|
||||||
VkImageLayout srcLayout,
|
VkImageLayout srcLayout,
|
||||||
|
@ -1057,31 +1057,35 @@ void GrVkGpu::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color
|
|||||||
inline bool can_copy_image(const GrSurface* dst,
|
inline bool can_copy_image(const GrSurface* dst,
|
||||||
const GrSurface* src,
|
const GrSurface* src,
|
||||||
const GrVkGpu* gpu) {
|
const GrVkGpu* gpu) {
|
||||||
if (src->asTexture() &&
|
// Currently we don't support msaa
|
||||||
dst->asTexture() &&
|
if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) ||
|
||||||
src->origin() == dst->origin() &&
|
(src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) {
|
||||||
src->config() == dst->config()) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
|
||||||
|
// as image usage flags.
|
||||||
|
if (src->origin() == dst->origin() &&
|
||||||
|
GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled
|
// How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled
|
||||||
// or the resolved image here?
|
// or the resolved image here? Im multisampled, Vulkan requires sample counts to be the same.
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
|
void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
|
||||||
GrSurface* src,
|
GrSurface* src,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
GrVkImage* srcImage,
|
||||||
const SkIRect& srcRect,
|
const SkIRect& srcRect,
|
||||||
const SkIPoint& dstPoint) {
|
const SkIPoint& dstPoint) {
|
||||||
SkASSERT(can_copy_image(dst, src, this));
|
SkASSERT(can_copy_image(dst, src, this));
|
||||||
|
|
||||||
// Insert memory barriers to switch src and dst to transfer_source and transfer_dst layouts
|
VkImageLayout origDstLayout = dstImage->currentLayout();
|
||||||
GrVkTexture* dstTex = static_cast<GrVkTexture*>(dst->asTexture());
|
VkImageLayout origSrcLayout = srcImage->currentLayout();
|
||||||
GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
|
|
||||||
|
|
||||||
VkImageLayout origDstLayout = dstTex->currentLayout();
|
|
||||||
VkImageLayout origSrcLayout = srcTex->currentLayout();
|
|
||||||
|
|
||||||
VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
|
VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
|
||||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
@ -1091,13 +1095,13 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
|
|||||||
VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
|
VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
|
||||||
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
dstTex->setImageLayout(this,
|
dstImage->setImageLayout(this,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
srcAccessMask,
|
srcAccessMask,
|
||||||
dstAccessMask,
|
dstAccessMask,
|
||||||
srcStageMask,
|
srcStageMask,
|
||||||
dstStageMask,
|
dstStageMask,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
|
srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
|
||||||
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
@ -1105,13 +1109,13 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
|
|||||||
srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
|
srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
|
||||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
srcTex->setImageLayout(this,
|
srcImage->setImageLayout(this,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
srcAccessMask,
|
srcAccessMask,
|
||||||
dstAccessMask,
|
dstAccessMask,
|
||||||
srcStageMask,
|
srcStageMask,
|
||||||
dstStageMask,
|
dstStageMask,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
// Flip rect if necessary
|
// Flip rect if necessary
|
||||||
SkIRect srcVkRect = srcRect;
|
SkIRect srcVkRect = srcRect;
|
||||||
@ -1133,14 +1137,121 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
|
|||||||
copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 0 };
|
copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 0 };
|
||||||
|
|
||||||
fCurrentCmdBuffer->copyImage(this,
|
fCurrentCmdBuffer->copyImage(this,
|
||||||
srcTex,
|
srcImage,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
dstTex,
|
dstImage,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
1,
|
1,
|
||||||
©Region);
|
©Region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool can_copy_as_blit(const GrSurface* dst,
|
||||||
|
const GrSurface* src,
|
||||||
|
const GrVkImage* dstImage,
|
||||||
|
const GrVkImage* srcImage,
|
||||||
|
const GrVkGpu* gpu) {
|
||||||
|
// We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
|
||||||
|
// as image usage flags.
|
||||||
|
const GrVkCaps& caps = gpu->vkCaps();
|
||||||
|
if (!caps.configCanBeDstofBlit(dst->config(), dstImage->isLinearTiled()) ||
|
||||||
|
!caps.configCanBeSrcofBlit(src->config(), srcImage->isLinearTiled())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cannot blit images that are multisampled. Will need to figure out if we can blit the
|
||||||
|
// resolved msaa though.
|
||||||
|
if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) ||
|
||||||
|
(src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrVkGpu::copySurfaceAsBlit(GrSurface* dst,
|
||||||
|
GrSurface* src,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
GrVkImage* srcImage,
|
||||||
|
const SkIRect& srcRect,
|
||||||
|
const SkIPoint& dstPoint) {
|
||||||
|
SkASSERT(can_copy_as_blit(dst, src, dstImage, srcImage, this));
|
||||||
|
|
||||||
|
VkImageLayout origDstLayout = dstImage->currentLayout();
|
||||||
|
VkImageLayout origSrcLayout = srcImage->currentLayout();
|
||||||
|
|
||||||
|
VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
|
||||||
|
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
|
||||||
|
VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
|
||||||
|
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
|
dstImage->setImageLayout(this,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
srcAccessMask,
|
||||||
|
dstAccessMask,
|
||||||
|
srcStageMask,
|
||||||
|
dstStageMask,
|
||||||
|
false);
|
||||||
|
|
||||||
|
srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
|
||||||
|
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
|
||||||
|
srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
|
||||||
|
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
|
srcImage->setImageLayout(this,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
srcAccessMask,
|
||||||
|
dstAccessMask,
|
||||||
|
srcStageMask,
|
||||||
|
dstStageMask,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// Flip rect if necessary
|
||||||
|
SkIRect srcVkRect;
|
||||||
|
SkIRect dstRect;
|
||||||
|
dstRect.fLeft = dstPoint.fX;
|
||||||
|
dstRect.fRight = dstPoint.fX + srcVkRect.width();
|
||||||
|
|
||||||
|
if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
|
||||||
|
srcVkRect.fTop = src->height() - srcRect.fBottom;
|
||||||
|
srcVkRect.fBottom = src->height() - srcRect.fTop;
|
||||||
|
} else {
|
||||||
|
srcVkRect = srcRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
|
||||||
|
dstRect.fTop = dst->height() - dstPoint.fY - srcVkRect.height();
|
||||||
|
} else {
|
||||||
|
dstRect.fTop = dstPoint.fY;
|
||||||
|
}
|
||||||
|
dstRect.fBottom = dstRect.fTop + srcVkRect.height();
|
||||||
|
|
||||||
|
// If we have different origins, we need to flip the top and bottom of the dst rect so that we
|
||||||
|
// get the correct origintation of the copied data.
|
||||||
|
if (src->origin() != dst->origin()) {
|
||||||
|
SkTSwap(dstRect.fTop, dstRect.fBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageBlit blitRegion;
|
||||||
|
memset(&blitRegion, 0, sizeof(VkImageBlit));
|
||||||
|
blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
blitRegion.srcOffsets[0] = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
|
||||||
|
blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 0 };
|
||||||
|
blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 };
|
||||||
|
blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 };
|
||||||
|
|
||||||
|
fCurrentCmdBuffer->blitImage(this,
|
||||||
|
srcImage,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
dstImage,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1,
|
||||||
|
&blitRegion,
|
||||||
|
VK_FILTER_NEAREST); // We never scale so any filter works here
|
||||||
|
}
|
||||||
|
|
||||||
inline bool can_copy_as_draw(const GrSurface* dst,
|
inline bool can_copy_as_draw(const GrSurface* dst,
|
||||||
const GrSurface* src,
|
const GrSurface* src,
|
||||||
const GrVkGpu* gpu) {
|
const GrVkGpu* gpu) {
|
||||||
@ -1158,8 +1269,28 @@ bool GrVkGpu::onCopySurface(GrSurface* dst,
|
|||||||
GrSurface* src,
|
GrSurface* src,
|
||||||
const SkIRect& srcRect,
|
const SkIRect& srcRect,
|
||||||
const SkIPoint& dstPoint) {
|
const SkIPoint& dstPoint) {
|
||||||
|
GrVkImage* dstImage;
|
||||||
|
GrVkImage* srcImage;
|
||||||
|
if (dst->asTexture()) {
|
||||||
|
dstImage = static_cast<GrVkTexture*>(dst->asTexture());
|
||||||
|
} else {
|
||||||
|
SkASSERT(dst->asRenderTarget());
|
||||||
|
dstImage = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
|
||||||
|
}
|
||||||
|
if (src->asTexture()) {
|
||||||
|
srcImage = static_cast<GrVkTexture*>(src->asTexture());
|
||||||
|
} else {
|
||||||
|
SkASSERT(src->asRenderTarget());
|
||||||
|
srcImage = static_cast<GrVkRenderTarget*>(src->asRenderTarget());
|
||||||
|
}
|
||||||
|
|
||||||
if (can_copy_image(dst, src, this)) {
|
if (can_copy_image(dst, src, this)) {
|
||||||
this->copySurfaceAsCopyImage(dst, src, srcRect, dstPoint);
|
this->copySurfaceAsCopyImage(dst, src, dstImage, srcImage, srcRect, dstPoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_copy_as_blit(dst, src, dstImage, srcImage, this)) {
|
||||||
|
this->copySurfaceAsBlit(dst, src, dstImage, srcImage, srcRect, dstPoint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +174,18 @@ private:
|
|||||||
|
|
||||||
void copySurfaceAsCopyImage(GrSurface* dst,
|
void copySurfaceAsCopyImage(GrSurface* dst,
|
||||||
GrSurface* src,
|
GrSurface* src,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
GrVkImage* srcImage,
|
||||||
const SkIRect& srcRect,
|
const SkIRect& srcRect,
|
||||||
const SkIPoint& dstPoint);
|
const SkIPoint& dstPoint);
|
||||||
|
|
||||||
|
void copySurfaceAsBlit(GrSurface* dst,
|
||||||
|
GrSurface* src,
|
||||||
|
GrVkImage* dstImage,
|
||||||
|
GrVkImage* srcImage,
|
||||||
|
const SkIRect& srcRect,
|
||||||
|
const SkIPoint& dstPoint);
|
||||||
|
|
||||||
void copySurfaceAsDraw(GrSurface* dst,
|
void copySurfaceAsDraw(GrSurface* dst,
|
||||||
GrSurface* src,
|
GrSurface* src,
|
||||||
const SkIRect& srcRect,
|
const SkIRect& srcRect,
|
||||||
|
Loading…
Reference in New Issue
Block a user