Vulkan: Implement basic Clear and ReadPixels.
This enables the simple operations clear test on Vulkan. The current
implementation is very synchronous - it will block and finish the
current command buffer if there is any possibility of a race.
BUG=angleproject:1319
Change-Id: If01fe9a19ed6f539639a38786193d3626164cada
Reviewed-on: https://chromium-review.googlesource.com/367754
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index e351dea..8d1e745 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -9,15 +9,59 @@
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
+#include <array>
+#include <vulkan/vulkan.h>
+
#include "common/debug.h"
+#include "image_util/imageformats.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/renderer_utils.h"
+#include "libANGLE/renderer/vulkan/ContextVk.h"
+#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
+#include "libANGLE/renderer/vulkan/RendererVk.h"
+#include "libANGLE/renderer/vulkan/SurfaceVk.h"
+#include "libANGLE/renderer/vulkan/formatutilsvk.h"
namespace rx
{
+namespace
+{
+
+gl::ErrorOrResult<const gl::InternalFormat *> GetReadAttachmentInfo(
+ const gl::FramebufferAttachment *readAttachment)
+{
+ RenderTargetVk *renderTarget = nullptr;
+ ANGLE_TRY(readAttachment->getRenderTarget(&renderTarget));
+
+ GLenum implFormat = renderTarget->format->format().fboImplementationInternalFormat;
+ return &gl::GetInternalFormatInfo(implFormat);
+}
+
+} // anonymous namespace
+
+// static
+FramebufferVk *FramebufferVk::CreateUserFBO(const gl::FramebufferState &state)
+{
+ return new FramebufferVk(state);
+}
+
+// static
+FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state,
+ WindowSurfaceVk *backbuffer)
+{
+ return new FramebufferVk(state, backbuffer);
+}
+
FramebufferVk::FramebufferVk(const gl::FramebufferState &state) : FramebufferImpl(state)
{
}
+FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer)
+ : FramebufferImpl(state)
+{
+}
+
FramebufferVk::~FramebufferVk()
{
}
@@ -44,8 +88,59 @@
gl::Error FramebufferVk::clear(ContextImpl *context, GLbitfield mask)
{
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION);
+ ContextVk *contextVk = GetAs<ContextVk>(context);
+
+ if (mState.getDepthAttachment() && (mask & GL_DEPTH_BUFFER_BIT) != 0)
+ {
+ // TODO(jmadill): Depth clear
+ UNIMPLEMENTED();
+ }
+
+ if (mState.getStencilAttachment() && (mask & GL_STENCIL_BUFFER_BIT) != 0)
+ {
+ // TODO(jmadill): Stencil clear
+ UNIMPLEMENTED();
+ }
+
+ if ((mask & GL_COLOR_BUFFER_BIT) == 0)
+ {
+ return gl::NoError();
+ }
+
+ const auto &glState = context->getGLState();
+ const auto &clearColor = glState.getColorClearValue();
+ VkClearColorValue clearColorValue;
+ clearColorValue.float32[0] = clearColor.red;
+ clearColorValue.float32[1] = clearColor.green;
+ clearColorValue.float32[2] = clearColor.blue;
+ clearColorValue.float32[3] = clearColor.alpha;
+
+ // TODO(jmadill): Scissored clears.
+ const auto *attachment = mState.getFirstNonNullAttachment();
+ ASSERT(attachment && attachment->isAttached());
+ const auto &size = attachment->getSize();
+ const gl::Rectangle renderArea(0, 0, size.width, size.height);
+
+ vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer();
+ ANGLE_TRY(commandBuffer->begin());
+
+ for (const auto &colorAttachment : mState.getColorAttachments())
+ {
+ if (colorAttachment.isAttached())
+ {
+ RenderTargetVk *renderTarget = nullptr;
+ ANGLE_TRY(colorAttachment.getRenderTarget(&renderTarget));
+ renderTarget->image->changeLayoutTop(
+ VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandBuffer);
+ commandBuffer->clearSingleColorImage(*renderTarget->image, clearColorValue);
+ }
+ }
+
+ commandBuffer->end();
+
+ ANGLE_TRY(contextVk->submitCommands(*commandBuffer));
+
+ return gl::NoError();
}
gl::Error FramebufferVk::clearBufferfv(ContextImpl *context,
@@ -87,14 +182,30 @@
GLenum FramebufferVk::getImplementationColorReadFormat() const
{
- UNIMPLEMENTED();
- return GLenum();
+ auto errOrResult = GetReadAttachmentInfo(mState.getReadAttachment());
+
+ // TODO(jmadill): Handle getRenderTarget error.
+ if (errOrResult.isError())
+ {
+ ERR("Internal error in FramebufferVk::getImplementationColorReadFormat.");
+ return GL_NONE;
+ }
+
+ return errOrResult.getResult()->format;
}
GLenum FramebufferVk::getImplementationColorReadType() const
{
- UNIMPLEMENTED();
- return GLenum();
+ auto errOrResult = GetReadAttachmentInfo(mState.getReadAttachment());
+
+ // TODO(jmadill): Handle getRenderTarget error.
+ if (errOrResult.isError())
+ {
+ ERR("Internal error in FramebufferVk::getImplementationColorReadFormat.");
+ return GL_NONE;
+ }
+
+ return errOrResult.getResult()->type;
}
gl::Error FramebufferVk::readPixels(ContextImpl *context,
@@ -103,8 +214,65 @@
GLenum type,
GLvoid *pixels) const
{
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION);
+ const auto &glState = context->getGLState();
+ const auto *readFramebuffer = glState.getReadFramebuffer();
+ const auto *readAttachment = readFramebuffer->getReadColorbuffer();
+
+ RenderTargetVk *renderTarget = nullptr;
+ ANGLE_TRY(readAttachment->getRenderTarget(&renderTarget));
+
+ ContextVk *contextVk = GetAs<ContextVk>(context);
+ RendererVk *renderer = contextVk->getRenderer();
+
+ vk::Image *readImage = renderTarget->image;
+ vk::StagingImage stagingImage;
+ ANGLE_TRY_RESULT(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format,
+ renderTarget->extents),
+ stagingImage);
+
+ vk::CommandBuffer *commandBuffer = contextVk->getCommandBuffer();
+ commandBuffer->begin();
+ stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
+ commandBuffer);
+
+ gl::Box copyRegion;
+ copyRegion.x = area.x;
+ copyRegion.y = area.y;
+ copyRegion.z = 0;
+ copyRegion.width = area.width;
+ copyRegion.height = area.height;
+ copyRegion.depth = 1;
+
+ readImage->changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ commandBuffer);
+ commandBuffer->copySingleImage(*readImage, stagingImage.getImage(), copyRegion,
+ VK_IMAGE_ASPECT_COLOR_BIT);
+ commandBuffer->end();
+
+ ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
+
+ // TODO(jmadill): parameters
+ uint8_t *mapPointer = nullptr;
+ ANGLE_TRY(stagingImage.getDeviceMemory().map(0, stagingImage.getSize(), 0, &mapPointer));
+
+ const auto &angleFormat = renderTarget->format->format();
+
+ // TODO(jmadill): Use pixel bytes from the ANGLE format directly.
+ const auto &glFormat = gl::GetInternalFormatInfo(angleFormat.glInternalFormat);
+ int inputPitch = glFormat.pixelBytes * area.width;
+
+ PackPixelsParams params;
+ params.area = area;
+ params.format = format;
+ params.type = type;
+ params.outputPitch = inputPitch;
+ params.pack = glState.getPackState();
+
+ PackPixels(params, angleFormat, inputPitch, mapPointer, reinterpret_cast<uint8_t *>(pixels));
+
+ stagingImage.getDeviceMemory().unmap();
+
+ return vk::NoError();
}
gl::Error FramebufferVk::blit(ContextImpl *context,
@@ -125,7 +293,7 @@
void FramebufferVk::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
{
- UNIMPLEMENTED();
+ // TODO(jmadill): Smarter update.
}
} // namespace rx