Commit 018709fd by Luc Ferron Committed by Commit Bot

Vulkan: Basic support of copySubImage

- Implement basic path that does a cpu readback for everything and establish conformance for every case except the ones that need conversion. - Enables most copy sub image dEQP tests. Bug: angleproject:2501 Change-Id: Ib67c184894625dde850f320c40fe51fe70ba974f Reviewed-on: https://chromium-review.googlesource.com/1054387 Commit-Queue: Luc Ferron <lucferron@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e943df22
......@@ -277,46 +277,12 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
void *pixels)
{
const gl::State &glState = context->getGLState();
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice();
RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
RenderTargetVk *renderTarget = getColorReadRenderTarget();
ASSERT(renderTarget);
vk::ImageHelper stagingImage;
ANGLE_TRY(stagingImage.init2DStaging(
device, renderer->getMemoryProperties(), renderTarget->image->getFormat(),
gl::Extents(area.width, area.height, 1), vk::StagingUsage::Read));
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
stagingImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
vk::ImageHelper::Copy(renderTarget->image, &stagingImage, gl::Offset(area.x, area.y, 0),
gl::Offset(), gl::Extents(area.width, area.height, 1),
VK_IMAGE_ASPECT_COLOR_BIT, commandBuffer);
// Triggers a full finish.
// TODO(jmadill): Don't block on asynchronous readback.
ANGLE_TRY(renderer->finish(context));
// TODO(jmadill): parameters
uint8_t *mapPointer = nullptr;
ANGLE_TRY(stagingImage.getDeviceMemory().map(device, 0, stagingImage.getAllocatedMemorySize(),
0, &mapPointer));
const angle::Format &angleFormat = renderTarget->image->getFormat().textureFormat();
GLuint outputPitch = angleFormat.pixelBytes * area.width;
// Get the staging image pitch and use it to pack the pixels later.
VkSubresourceLayout subresourceLayout;
stagingImage.getImage().getSubresourceLayout(device, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
&subresourceLayout);
PackPixelsParams params;
params.area = area;
params.format = format;
......@@ -325,13 +291,16 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
params.packBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelPack);
params.pack = glState.getPackState();
PackPixels(params, angleFormat, static_cast<int>(subresourceLayout.rowPitch), mapPointer,
reinterpret_cast<uint8_t *>(pixels));
stagingImage.getDeviceMemory().unmap(device);
renderer->releaseObject(renderer->getCurrentQueueSerial(), &stagingImage);
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteResource(vk::GetImpl(context)->getRenderer(), &commandBuffer));
return ReadPixelsFromRenderTarget(context, area, params, renderTarget, commandBuffer, pixels);
}
return vk::NoError();
RenderTargetVk *FramebufferVk::getColorReadRenderTarget()
{
RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
ASSERT(renderTarget && renderTarget->image->valid());
return renderTarget;
}
gl::Error FramebufferVk::blit(const gl::Context *context,
......@@ -807,4 +776,53 @@ void FramebufferVk::updateActiveColorMasks(size_t colorIndex, bool r, bool g, bo
mActiveColorComponentMasks[2].set(colorIndex, b);
mActiveColorComponentMasks[3].set(colorIndex, a);
}
gl::Error ReadPixelsFromRenderTarget(const gl::Context *context,
const gl::Rectangle &area,
const PackPixelsParams &packPixelsParams,
RenderTargetVk *renderTarget,
vk::CommandBuffer *commandBuffer,
void *pixels)
{
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice();
vk::ImageHelper stagingImage;
ANGLE_TRY(stagingImage.init2DStaging(
device, renderer->getMemoryProperties(), renderTarget->image->getFormat(),
gl::Extents(area.width, area.height, 1), vk::StagingUsage::Read));
stagingImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
vk::ImageHelper::Copy(renderTarget->image, &stagingImage, gl::Offset(area.x, area.y, 0),
gl::Offset(), gl::Extents(area.width, area.height, 1),
VK_IMAGE_ASPECT_COLOR_BIT, commandBuffer);
// Triggers a full finish.
// TODO(jmadill): Don't block on asynchronous readback.
ANGLE_TRY(renderer->finish(context));
// TODO(jmadill): parameters
uint8_t *mapPointer = nullptr;
ANGLE_TRY(stagingImage.getDeviceMemory().map(device, 0, stagingImage.getAllocatedMemorySize(),
0, &mapPointer));
const angle::Format &angleFormat = renderTarget->image->getFormat().textureFormat();
// Get the staging image pitch and use it to pack the pixels later.
VkSubresourceLayout subresourceLayout;
stagingImage.getImage().getSubresourceLayout(device, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
&subresourceLayout);
PackPixels(packPixelsParams, angleFormat, static_cast<int>(subresourceLayout.rowPitch),
mapPointer, reinterpret_cast<uint8_t *>(pixels));
stagingImage.getDeviceMemory().unmap(device);
renderer->releaseObject(renderer->getCurrentQueueSerial(), &stagingImage);
return vk::NoError();
}
} // namespace rx
......@@ -71,7 +71,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
GLenum format,
GLenum type,
void *pixels) override;
RenderTargetVk *getColorReadRenderTarget();
gl::Error blit(const gl::Context *context,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
......@@ -120,6 +120,13 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
VkDescriptorSet mMaskedClearDescriptorSet;
};
gl::Error ReadPixelsFromRenderTarget(const gl::Context *context,
const gl::Rectangle &area,
const PackPixelsParams &packPixelsParams,
RenderTargetVk *renderTarget,
vk::CommandBuffer *commandBuffer,
void *pixels);
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_
......@@ -12,6 +12,7 @@
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
......@@ -146,21 +147,19 @@ gl::Error PixelBuffer::stageSubresourceUpdate(ContextVk *contextVk,
return gl::NoError();
}
gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk,
vk::CommandBuffer *commandBuffer,
const gl::ImageIndex &index,
const gl::Rectangle &sourceArea,
const gl::Offset dstOffset,
const gl::Extents dstExtent,
const gl::InternalFormat &formatInfo,
GLenum type,
vk::ImageHelper &srcImageHelper)
gl::Error PixelBuffer::stageSubresourceUpdateFromRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Rectangle &sourceArea,
const gl::Offset &dstOffset,
const gl::Extents &dstExtent,
const gl::InternalFormat &formatInfo,
vk::CommandBuffer *commandBuffer,
RenderTargetVk *renderTarget)
{
// If the extents and offset is outside the source image, we need to clip.
gl::Rectangle clippedRectangle;
if (!ClipRectangle(sourceArea,
gl::Rectangle(0, 0, srcImageHelper.getExtents().width,
srcImageHelper.getExtents().height),
const gl::Extents imageExtents = renderTarget->image->getExtents();
if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, imageExtents.width, imageExtents.height),
&clippedRectangle))
{
// Empty source area, nothing to do.
......@@ -168,10 +167,11 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk,
}
// 1- obtain a buffer handle to copy to
RendererVk *renderer = contextVk->getRenderer();
RendererVk *renderer = GetImplAs<ContextVk>(context)->getRenderer();
const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
const angle::Format &storageFormat = vkFormat.textureFormat();
LoadImageFunctionInfo loadFunction = vkFormat.loadFunctions(formatInfo.type);
size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width;
size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
......@@ -181,36 +181,38 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk,
uint8_t *stagingPointer = nullptr;
bool newBufferAllocated = false;
uint32_t stagingOffset = 0;
size_t allocationSize = outputDepthPitch * 1;
// The destination is only one layer deep.
size_t allocationSize = outputDepthPitch;
mStagingBuffer.allocate(renderer, allocationSize, &stagingPointer, &bufferHandle,
&stagingOffset, &newBufferAllocated);
// 2- copy the source image region to the pixel buffer.
VkBufferImageCopy copyToBuffer;
copyToBuffer.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
copyToBuffer.bufferRowLength = clippedRectangle.width;
copyToBuffer.bufferImageHeight = clippedRectangle.height;
copyToBuffer.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToBuffer.imageSubresource.mipLevel = 0;
copyToBuffer.imageSubresource.baseArrayLayer = 0;
copyToBuffer.imageSubresource.layerCount = 1;
copyToBuffer.imageOffset.x = clippedRectangle.x;
copyToBuffer.imageOffset.y = clippedRectangle.y;
copyToBuffer.imageOffset.z = 0;
copyToBuffer.imageExtent.width = clippedRectangle.width;
copyToBuffer.imageExtent.height = clippedRectangle.height;
copyToBuffer.imageExtent.depth = 1;
srcImageHelper.changeLayoutWithStages(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
commandBuffer->copyImageToBuffer(srcImageHelper.getImage(), srcImageHelper.getCurrentLayout(),
bufferHandle, 1, &copyToBuffer);
// 2- copy the source image region to the pixel buffer using a cpu readback
if (loadFunction.requiresConversion)
{
// TODO(lucferron): This needs additional work, we will read into a temp buffer and then
// use the loadFunction to read the data to our PixelBuffer.
// http://anglebug.com/2501
UNIMPLEMENTED();
}
else
{
PackPixelsParams params;
params.area = sourceArea;
params.format = formatInfo.internalFormat;
params.type = formatInfo.type;
params.outputPitch = static_cast<GLuint>(outputRowPitch);
params.packBuffer = nullptr;
params.pack = gl::PixelPackState();
ANGLE_TRY(ReadPixelsFromRenderTarget(context, sourceArea, params, renderTarget,
commandBuffer, stagingPointer));
}
// 3- enqueue the destination image subresource update
VkBufferImageCopy copyToImage;
copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
copyToImage.bufferRowLength = clippedRectangle.width;
copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0.
copyToImage.bufferImageHeight = clippedRectangle.height;
copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToImage.imageSubresource.mipLevel = index.getLevelIndex();
......@@ -406,8 +408,38 @@ gl::Error TextureVk::copySubImage(const gl::Context *context,
const gl::Rectangle &sourceArea,
gl::Framebuffer *source)
{
UNIMPLEMENTED();
return gl::InternalError();
gl::Extents fbSize = source->getReadColorbuffer()->getSize();
gl::Rectangle clippedSourceArea;
if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
&clippedSourceArea))
{
return gl::NoError();
}
const gl::Offset modifiedDestOffset(destOffset.x + sourceArea.x - sourceArea.x,
destOffset.y + sourceArea.y - sourceArea.y, 0);
ContextVk *contextVk = vk::GetImpl(context);
FramebufferVk *framebufferVk = vk::GetImpl(source);
RenderTargetVk *renderTarget = framebufferVk->getColorReadRenderTarget();
const gl::InternalFormat &currentFormat = *mState.getBaseLevelDesc().format.info;
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(framebufferVk->beginWriteResource(contextVk->getRenderer(), &commandBuffer));
// For now, favor conformance. We do a CPU readback that does the conversion, and then stage the
// change to the pixel buffer.
// Eventually we can improve this easily by implementing vkCmdBlitImage to do the conversion
// when its supported.
ANGLE_TRY(mPixelBuffer.stageSubresourceUpdateFromRenderTarget(
context, index, clippedSourceArea, modifiedDestOffset,
gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), currentFormat,
commandBuffer, renderTarget));
vk::CommandGraphNode *writingNode = getNewWritingNode(contextVk->getRenderer());
framebufferVk->onReadResource(writingNode, contextVk->getRenderer()->getCurrentQueueSerial());
return gl::NoError();
}
vk::Error TextureVk::getCommandBufferForWrite(RendererVk *renderer,
......
......@@ -35,15 +35,14 @@ class PixelBuffer final : angle::NonCopyable
GLenum type,
const uint8_t *pixels);
gl::Error stageSubresourceUpdateFromImage(ContextVk *contextVk,
vk::CommandBuffer *commandBuffer,
const gl::ImageIndex &index,
const gl::Rectangle &sourceArea,
gl::Offset dstOffset,
gl::Extents dstExtent,
const gl::InternalFormat &formatInfo,
GLenum type,
vk::ImageHelper &srcImageHelper);
gl::Error stageSubresourceUpdateFromRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Rectangle &sourceArea,
const gl::Offset &dstOffset,
const gl::Extents &dstExtent,
const gl::InternalFormat &formatInfo,
vk::CommandBuffer *commandBuffer,
RenderTargetVk *renderTarget);
vk::Error flushUpdatesToImage(RendererVk *renderer,
vk::ImageHelper *image,
......
......@@ -195,7 +195,10 @@
2161 VULKAN : dEQP-GLES2.functional.shaders.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.mipmap.2d.generate.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.mipmap.cube.generate.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.specification.basic_copytex* = SKIP
2500 VULKAN : dEQP-GLES2.functional.texture.specification.basic_copyteximage2d.* = SKIP
2501 VULKAN : dEQP-GLES2.functional.texture.specification.basic_copytexsubimage2d.2d_rgb = SKIP
2501 VULKAN : dEQP-GLES2.functional.texture.specification.basic_copytexsubimage2d.cube_rgb = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.completeness.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.vertex.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.fragment_ops.random.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.fragment_ops.interaction.* = SKIP
......
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