Commit 26581113 by Luc Ferron Committed by Commit Bot

Vulkan: Support for framebuffer blit extension

- No support for formats that do not support vulkan blit. - The depth/stencil format used in the tests do not support blit, so currently no tests validate the depth/stencil blits. Bug: angleproject:2643 Change-Id: I89a0d5b102396d8254fe272681326615bd6800ed Reviewed-on: https://chromium-review.googlesource.com/1111611Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Luc Ferron <lucferron@chromium.org>
parent f97641c1
...@@ -39,6 +39,25 @@ const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context, ...@@ -39,6 +39,25 @@ const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context,
renderTarget->getImageFormat().textureFormat().fboImplementationInternalFormat; renderTarget->getImageFormat().textureFormat().fboImplementationInternalFormat;
return gl::GetSizedInternalFormatInfo(implFormat); return gl::GetSizedInternalFormatInfo(implFormat);
} }
bool HasSrcAndDstBlitProperties(const VkPhysicalDevice &physicalDevice,
RenderTargetVk *srcRenderTarget,
RenderTargetVk *dstRenderTarget)
{
VkFormatProperties drawImageProperties;
vk::GetFormatProperties(physicalDevice, srcRenderTarget->getImageFormat().vkTextureFormat,
&drawImageProperties);
VkFormatProperties readImageProperties;
vk::GetFormatProperties(physicalDevice, dstRenderTarget->getImageFormat().vkTextureFormat,
&readImageProperties);
// Verifies if the draw and read images have the necessary prerequisites for blitting.
return (IsMaskFlagSet<VkFormatFeatureFlags>(drawImageProperties.optimalTilingFeatures,
VK_FORMAT_FEATURE_BLIT_DST_BIT) &&
IsMaskFlagSet<VkFormatFeatureFlags>(readImageProperties.optimalTilingFeatures,
VK_FORMAT_FEATURE_BLIT_SRC_BIT));
}
} // anonymous namespace } // anonymous namespace
// static // static
...@@ -175,7 +194,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -175,7 +194,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
const VkClearDepthStencilValue &clearDepthStencilValue = const VkClearDepthStencilValue &clearDepthStencilValue =
contextVk->getClearDepthStencilValue().depthStencil; contextVk->getClearDepthStencilValue().depthStencil;
RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil(); RenderTargetVk *renderTarget = mRenderTargetCache.getDepthStencil();
const angle::Format &format = renderTarget->getImageFormat().textureFormat(); const angle::Format &format = renderTarget->getImageFormat().textureFormat();
const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); const VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format);
...@@ -202,7 +221,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -202,7 +221,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
for (size_t colorIndex : mState.getEnabledDrawBuffers()) for (size_t colorIndex : mState.getEnabledDrawBuffers())
{ {
VkClearColorValue modifiedClearColorValue = clearColorValue; VkClearColorValue modifiedClearColorValue = clearColorValue;
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex];
// Its possible we're clearing a render target that has no alpha channel but we represent it // Its possible we're clearing a render target that has no alpha channel but we represent it
// with a texture that has one. We must not affect its alpha channel no matter what the // with a texture that has one. We must not affect its alpha channel no matter what the
...@@ -318,6 +337,11 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context, ...@@ -318,6 +337,11 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
return gl::NoError(); return gl::NoError();
} }
RenderTargetVk *FramebufferVk::getDepthStencilRenderTarget() const
{
return mRenderTargetCache.getDepthStencil();
}
RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const
{ {
RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState); RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
...@@ -331,11 +355,145 @@ gl::Error FramebufferVk::blit(const gl::Context *context, ...@@ -331,11 +355,145 @@ gl::Error FramebufferVk::blit(const gl::Context *context,
GLbitfield mask, GLbitfield mask,
GLenum filter) GLenum filter)
{ {
// TODO(lucferron): Implement this ContextVk *contextVk = vk::GetImpl(context);
// Should enable the BlitFramebufferANGLETest tests in angle_end2end_tests RendererVk *renderer = contextVk->getRenderer();
// http://anglebug.com/2643
UNIMPLEMENTED(); const gl::State &glState = context->getGLState();
return gl::InternalError(); const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer();
const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr;
bool blitColorBuffer = (mask & GL_COLOR_BUFFER_BIT) != 0;
bool blitDepthBuffer = (mask & GL_DEPTH_BUFFER_BIT) != 0;
bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0;
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
FramebufferVk *sourceFramebufferVk = vk::GetImpl(sourceFramebuffer);
if (blitColorBuffer)
{
RenderTargetVk *readRenderTarget = sourceFramebufferVk->getColorReadRenderTarget();
for (size_t colorAttachment : mState.getEnabledDrawBuffers())
{
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorAttachment];
ASSERT(drawRenderTarget);
ASSERT(HasSrcAndDstBlitProperties(renderer->getPhysicalDevice(), readRenderTarget,
drawRenderTarget));
ANGLE_TRY(blitImpl(commandBuffer, sourceArea, destArea, readRenderTarget,
drawRenderTarget, filter, scissor, true, false, false));
}
}
if (blitDepthBuffer || blitStencilBuffer)
{
RenderTargetVk *readRenderTarget = sourceFramebufferVk->getDepthStencilRenderTarget();
ASSERT(readRenderTarget);
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil();
if (HasSrcAndDstBlitProperties(renderer->getPhysicalDevice(), readRenderTarget,
drawRenderTarget))
{
ANGLE_TRY(blitImpl(commandBuffer, sourceArea, destArea, readRenderTarget,
drawRenderTarget, filter, scissor, false, blitDepthBuffer,
blitStencilBuffer));
}
else
{
// TODO(lucferron): Support framebuffer blit with a slower path.
// http://anglebug.com/2643
UNIMPLEMENTED();
return gl::InternalError();
}
}
return gl::NoError();
}
gl::Error FramebufferVk::blitImpl(vk::CommandBuffer *commandBuffer,
const gl::Rectangle &readRectIn,
const gl::Rectangle &drawRectIn,
RenderTargetVk *readRenderTarget,
RenderTargetVk *drawRenderTarget,
GLenum filter,
const gl::Rectangle *scissor,
bool colorBlit,
bool depthBlit,
bool stencilBlit)
{
// Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
// it should never be the case that both color and depth/stencil need to be blitted at
// at the same time.
ASSERT(colorBlit != (depthBlit || stencilBlit));
gl::Rectangle scissoredDrawRect = drawRectIn;
gl::Rectangle scissoredReadRect = readRectIn;
if (scissor)
{
if (!ClipRectangle(drawRectIn, *scissor, &scissoredDrawRect))
{
return gl::NoError();
}
if (!ClipRectangle(readRectIn, *scissor, &scissoredReadRect))
{
return gl::NoError();
}
}
const gl::Extents sourceFrameBufferExtents = readRenderTarget->getImageExtents();
// After cropping for the scissor, we also want to crop for the size of the buffers.
gl::Rectangle readFrameBufferBounds(0, 0, sourceFrameBufferExtents.width,
sourceFrameBufferExtents.height);
if (!ClipRectangle(scissoredReadRect, readFrameBufferBounds, &scissoredReadRect))
{
return gl::NoError();
}
const vk::Format &readImageFormat = readRenderTarget->getImageFormat();
VkImageAspectFlags aspectMask =
colorBlit ? VK_IMAGE_ASPECT_COLOR_BIT
: vk::GetDepthStencilAspectFlags(readImageFormat.textureFormat());
vk::ImageHelper *srcImage = readRenderTarget->getImageForRead(
this, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, aspectMask, commandBuffer);
VkImageBlit blit = {};
blit.srcOffsets[0] = {scissoredReadRect.x0(), scissoredReadRect.y0(), 0};
blit.srcOffsets[1] = {scissoredReadRect.x1(), scissoredReadRect.y1(), 1};
blit.srcSubresource.aspectMask = aspectMask;
blit.srcSubresource.mipLevel = 0;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstSubresource.aspectMask = aspectMask;
blit.dstSubresource.mipLevel = 0;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
const gl::Extents &drawFrameBufferExtents = drawRenderTarget->getImageExtents();
gl::Rectangle drawFrameBufferBounds(0, 0, drawFrameBufferExtents.width,
drawFrameBufferExtents.height);
if (!ClipRectangle(scissoredDrawRect, drawFrameBufferBounds, &scissoredDrawRect))
{
return gl::NoError();
}
blit.dstOffsets[0] = {scissoredDrawRect.x0(), scissoredDrawRect.y0(), 0};
blit.dstOffsets[1] = {scissoredDrawRect.x1(), scissoredDrawRect.y1(), 1};
vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(this);
// Requirement of the copyImageToBuffer, the dst image must be in
// VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout.
dstImage->changeLayoutWithStages(aspectMask, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
gl_vk::GetFilter(filter));
return gl::NoError();
} }
bool FramebufferVk::checkStatus(const gl::Context *context) const bool FramebufferVk::checkStatus(const gl::Context *context) const
......
...@@ -72,6 +72,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -72,6 +72,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
GLenum format, GLenum format,
GLenum type, GLenum type,
void *pixels) override; void *pixels) override;
gl::Error blit(const gl::Context *context, gl::Error blit(const gl::Context *context,
const gl::Rectangle &sourceArea, const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea, const gl::Rectangle &destArea,
...@@ -86,7 +87,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -86,7 +87,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
gl::Error getSamplePosition(const gl::Context *context, gl::Error getSamplePosition(const gl::Context *context,
size_t index, size_t index,
GLfloat *xy) const override; GLfloat *xy) const override;
RenderTargetVk *getDepthStencilRenderTarget() const;
const vk::RenderPassDesc &getRenderPassDesc(); const vk::RenderPassDesc &getRenderPassDesc();
gl::Error getCommandBufferForDraw(ContextVk *contextVk, gl::Error getCommandBufferForDraw(ContextVk *contextVk,
vk::CommandBuffer **commandBufferOut, vk::CommandBuffer **commandBufferOut,
...@@ -114,6 +115,18 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -114,6 +115,18 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
bool clearStencil); bool clearStencil);
gl::Error clearWithDraw(const gl::Context *context, VkColorComponentFlags colorMaskFlags); gl::Error clearWithDraw(const gl::Context *context, VkColorComponentFlags colorMaskFlags);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a); void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
gl::Error blitImpl(vk::CommandBuffer *commandBuffer,
const gl::Rectangle &readRectIn,
const gl::Rectangle &drawRectIn,
RenderTargetVk *readRenderTarget,
RenderTargetVk *drawRenderTarget,
GLenum filter,
const gl::Rectangle *scissor,
bool colorBlit,
bool depthBlit,
bool stencilBlit);
RenderTargetVk *getColorReadRenderTarget() const; RenderTargetVk *getColorReadRenderTarget() const;
WindowSurfaceVk *mBackbuffer; WindowSurfaceVk *mBackbuffer;
......
...@@ -34,6 +34,7 @@ void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties, ...@@ -34,6 +34,7 @@ void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties,
outExtensions->mapBuffer = true; outExtensions->mapBuffer = true;
outExtensions->mapBufferRange = true; outExtensions->mapBufferRange = true;
outExtensions->textureStorage = true; outExtensions->textureStorage = true;
outExtensions->framebufferBlit = true;
// TODO(lucferron): Eventually remove everything above this line in this function as the caps // TODO(lucferron): Eventually remove everything above this line in this function as the caps
// get implemented. // get implemented.
......
...@@ -570,6 +570,11 @@ TEST_P(BlitFramebufferANGLETest, ReverseOversizedBlit) ...@@ -570,6 +570,11 @@ TEST_P(BlitFramebufferANGLETest, ReverseOversizedBlit)
// blit from user-created FBO to system framebuffer, with depth buffer. // blit from user-created FBO to system framebuffer, with depth buffer.
TEST_P(BlitFramebufferANGLETest, BlitWithDepth) TEST_P(BlitFramebufferANGLETest, BlitWithDepth)
{ {
// TODO(lucferron): The format used is not supported for vkCmdBlitImage so we'll need to
// implement a slow path.
// http://anglebug.com/2643
ANGLE_SKIP_TEST_IF(IsVulkan());
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit")); ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
...@@ -609,6 +614,11 @@ TEST_P(BlitFramebufferANGLETest, BlitWithDepth) ...@@ -609,6 +614,11 @@ TEST_P(BlitFramebufferANGLETest, BlitWithDepth)
// blit from system FBO to user-created framebuffer, with depth buffer. // blit from system FBO to user-created framebuffer, with depth buffer.
TEST_P(BlitFramebufferANGLETest, ReverseBlitWithDepth) TEST_P(BlitFramebufferANGLETest, ReverseBlitWithDepth)
{ {
// TODO(lucferron): The format used is not supported for vkCmdBlitImage so we'll need to
// implement a slow path.
// http://anglebug.com/2643
ANGLE_SKIP_TEST_IF(IsVulkan());
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit")); ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO); glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
...@@ -781,6 +791,11 @@ TEST_P(BlitFramebufferANGLETest, BlitWithMissingAttachments) ...@@ -781,6 +791,11 @@ TEST_P(BlitFramebufferANGLETest, BlitWithMissingAttachments)
TEST_P(BlitFramebufferANGLETest, BlitStencil) TEST_P(BlitFramebufferANGLETest, BlitStencil)
{ {
// TODO(lucferron): The format used is not supported for vkCmdBlitImage so we'll need to
// implement a slow path.
// http://anglebug.com/2643
ANGLE_SKIP_TEST_IF(IsVulkan());
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit")); ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_ANGLE_framebuffer_blit"));
// TODO(jmadill): Figure out if we can fix this on D3D9. // TODO(jmadill): Figure out if we can fix this on D3D9.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment