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, ...@@ -277,46 +277,12 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
void *pixels) void *pixels)
{ {
const gl::State &glState = context->getGLState(); const gl::State &glState = context->getGLState();
ContextVk *contextVk = vk::GetImpl(context); RenderTargetVk *renderTarget = getColorReadRenderTarget();
RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice();
RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
ASSERT(renderTarget); 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(); const angle::Format &angleFormat = renderTarget->image->getFormat().textureFormat();
GLuint outputPitch = angleFormat.pixelBytes * area.width; 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; PackPixelsParams params;
params.area = area; params.area = area;
params.format = format; params.format = format;
...@@ -325,13 +291,16 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context, ...@@ -325,13 +291,16 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
params.packBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelPack); params.packBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelPack);
params.pack = glState.getPackState(); params.pack = glState.getPackState();
PackPixels(params, angleFormat, static_cast<int>(subresourceLayout.rowPitch), mapPointer, vk::CommandBuffer *commandBuffer = nullptr;
reinterpret_cast<uint8_t *>(pixels)); ANGLE_TRY(beginWriteResource(vk::GetImpl(context)->getRenderer(), &commandBuffer));
return ReadPixelsFromRenderTarget(context, area, params, renderTarget, commandBuffer, pixels);
stagingImage.getDeviceMemory().unmap(device); }
renderer->releaseObject(renderer->getCurrentQueueSerial(), &stagingImage);
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, gl::Error FramebufferVk::blit(const gl::Context *context,
...@@ -807,4 +776,53 @@ void FramebufferVk::updateActiveColorMasks(size_t colorIndex, bool r, bool g, bo ...@@ -807,4 +776,53 @@ void FramebufferVk::updateActiveColorMasks(size_t colorIndex, bool r, bool g, bo
mActiveColorComponentMasks[2].set(colorIndex, b); mActiveColorComponentMasks[2].set(colorIndex, b);
mActiveColorComponentMasks[3].set(colorIndex, a); 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 } // namespace rx
...@@ -71,7 +71,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -71,7 +71,7 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
GLenum format, GLenum format,
GLenum type, GLenum type,
void *pixels) override; void *pixels) override;
RenderTargetVk *getColorReadRenderTarget();
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,
...@@ -120,6 +120,13 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -120,6 +120,13 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
VkDescriptorSet mMaskedClearDescriptorSet; 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 } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_ #endif // LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
...@@ -146,21 +147,19 @@ gl::Error PixelBuffer::stageSubresourceUpdate(ContextVk *contextVk, ...@@ -146,21 +147,19 @@ gl::Error PixelBuffer::stageSubresourceUpdate(ContextVk *contextVk,
return gl::NoError(); return gl::NoError();
} }
gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk, gl::Error PixelBuffer::stageSubresourceUpdateFromRenderTarget(const gl::Context *context,
vk::CommandBuffer *commandBuffer, const gl::ImageIndex &index,
const gl::ImageIndex &index, const gl::Rectangle &sourceArea,
const gl::Rectangle &sourceArea, const gl::Offset &dstOffset,
const gl::Offset dstOffset, const gl::Extents &dstExtent,
const gl::Extents dstExtent, const gl::InternalFormat &formatInfo,
const gl::InternalFormat &formatInfo, vk::CommandBuffer *commandBuffer,
GLenum type, RenderTargetVk *renderTarget)
vk::ImageHelper &srcImageHelper)
{ {
// If the extents and offset is outside the source image, we need to clip. // If the extents and offset is outside the source image, we need to clip.
gl::Rectangle clippedRectangle; gl::Rectangle clippedRectangle;
if (!ClipRectangle(sourceArea, const gl::Extents imageExtents = renderTarget->image->getExtents();
gl::Rectangle(0, 0, srcImageHelper.getExtents().width, if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, imageExtents.width, imageExtents.height),
srcImageHelper.getExtents().height),
&clippedRectangle)) &clippedRectangle))
{ {
// Empty source area, nothing to do. // Empty source area, nothing to do.
...@@ -168,10 +167,11 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk, ...@@ -168,10 +167,11 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk,
} }
// 1- obtain a buffer handle to copy to // 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 vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
const angle::Format &storageFormat = vkFormat.textureFormat(); const angle::Format &storageFormat = vkFormat.textureFormat();
LoadImageFunctionInfo loadFunction = vkFormat.loadFunctions(formatInfo.type);
size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width; size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width;
size_t outputDepthPitch = outputRowPitch * clippedRectangle.height; size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
...@@ -181,36 +181,38 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk, ...@@ -181,36 +181,38 @@ gl::Error PixelBuffer::stageSubresourceUpdateFromImage(ContextVk *contextVk,
uint8_t *stagingPointer = nullptr; uint8_t *stagingPointer = nullptr;
bool newBufferAllocated = false; bool newBufferAllocated = false;
uint32_t stagingOffset = 0; 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, mStagingBuffer.allocate(renderer, allocationSize, &stagingPointer, &bufferHandle,
&stagingOffset, &newBufferAllocated); &stagingOffset, &newBufferAllocated);
// 2- copy the source image region to the pixel buffer. // 2- copy the source image region to the pixel buffer using a cpu readback
VkBufferImageCopy copyToBuffer; if (loadFunction.requiresConversion)
copyToBuffer.bufferOffset = static_cast<VkDeviceSize>(stagingOffset); {
copyToBuffer.bufferRowLength = clippedRectangle.width; // TODO(lucferron): This needs additional work, we will read into a temp buffer and then
copyToBuffer.bufferImageHeight = clippedRectangle.height; // use the loadFunction to read the data to our PixelBuffer.
copyToBuffer.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // http://anglebug.com/2501
copyToBuffer.imageSubresource.mipLevel = 0; UNIMPLEMENTED();
copyToBuffer.imageSubresource.baseArrayLayer = 0; }
copyToBuffer.imageSubresource.layerCount = 1; else
copyToBuffer.imageOffset.x = clippedRectangle.x; {
copyToBuffer.imageOffset.y = clippedRectangle.y; PackPixelsParams params;
copyToBuffer.imageOffset.z = 0; params.area = sourceArea;
copyToBuffer.imageExtent.width = clippedRectangle.width; params.format = formatInfo.internalFormat;
copyToBuffer.imageExtent.height = clippedRectangle.height; params.type = formatInfo.type;
copyToBuffer.imageExtent.depth = 1; params.outputPitch = static_cast<GLuint>(outputRowPitch);
params.packBuffer = nullptr;
srcImageHelper.changeLayoutWithStages( params.pack = gl::PixelPackState();
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer); ANGLE_TRY(ReadPixelsFromRenderTarget(context, sourceArea, params, renderTarget,
commandBuffer, stagingPointer));
commandBuffer->copyImageToBuffer(srcImageHelper.getImage(), srcImageHelper.getCurrentLayout(), }
bufferHandle, 1, &copyToBuffer);
// 3- enqueue the destination image subresource update
VkBufferImageCopy copyToImage; VkBufferImageCopy copyToImage;
copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset); 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.bufferImageHeight = clippedRectangle.height;
copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToImage.imageSubresource.mipLevel = index.getLevelIndex(); copyToImage.imageSubresource.mipLevel = index.getLevelIndex();
...@@ -406,8 +408,38 @@ gl::Error TextureVk::copySubImage(const gl::Context *context, ...@@ -406,8 +408,38 @@ gl::Error TextureVk::copySubImage(const gl::Context *context,
const gl::Rectangle &sourceArea, const gl::Rectangle &sourceArea,
gl::Framebuffer *source) gl::Framebuffer *source)
{ {
UNIMPLEMENTED(); gl::Extents fbSize = source->getReadColorbuffer()->getSize();
return gl::InternalError(); 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, vk::Error TextureVk::getCommandBufferForWrite(RendererVk *renderer,
......
...@@ -35,15 +35,14 @@ class PixelBuffer final : angle::NonCopyable ...@@ -35,15 +35,14 @@ class PixelBuffer final : angle::NonCopyable
GLenum type, GLenum type,
const uint8_t *pixels); const uint8_t *pixels);
gl::Error stageSubresourceUpdateFromImage(ContextVk *contextVk, gl::Error stageSubresourceUpdateFromRenderTarget(const gl::Context *context,
vk::CommandBuffer *commandBuffer, const gl::ImageIndex &index,
const gl::ImageIndex &index, const gl::Rectangle &sourceArea,
const gl::Rectangle &sourceArea, const gl::Offset &dstOffset,
gl::Offset dstOffset, const gl::Extents &dstExtent,
gl::Extents dstExtent, const gl::InternalFormat &formatInfo,
const gl::InternalFormat &formatInfo, vk::CommandBuffer *commandBuffer,
GLenum type, RenderTargetVk *renderTarget);
vk::ImageHelper &srcImageHelper);
vk::Error flushUpdatesToImage(RendererVk *renderer, vk::Error flushUpdatesToImage(RendererVk *renderer,
vk::ImageHelper *image, vk::ImageHelper *image,
......
...@@ -195,7 +195,10 @@ ...@@ -195,7 +195,10 @@
2161 VULKAN : dEQP-GLES2.functional.shaders.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.shaders.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.texture.mipmap.2d.generate.* = 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.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.texture.vertex.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.fragment_ops.random.* = SKIP 2161 VULKAN : dEQP-GLES2.functional.fragment_ops.random.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.fragment_ops.interaction.* = 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