Commit e9dcffb1 by Ian Elliott Committed by Commit Bot

Vulkan: Enhance ReadPixels to deal with pre-rotation

Depending on the orientation, the source image may be row-major or column-major; with positive or negative x/y-axis pitches. Regardless of the orientation, the destination remains row-major. Bug: angleproject:4436 Bug: b/150329975 Change-Id: Ia1287f7036f07548d35128f1761feadf721cd78a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2191425Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Commit-Queue: Ian Elliott <ianelliott@google.com>
parent c6aef6dd
...@@ -205,11 +205,14 @@ void SetFloatUniformMatrixFast(unsigned int arrayElementOffset, ...@@ -205,11 +205,14 @@ void SetFloatUniformMatrixFast(unsigned int arrayElementOffset,
memcpy(targetData, valueData, matrixSize * count); memcpy(targetData, valueData, matrixSize * count);
} }
} // anonymous namespace } // anonymous namespace
PackPixelsParams::PackPixelsParams() PackPixelsParams::PackPixelsParams()
: destFormat(nullptr), outputPitch(0), packBuffer(nullptr), offset(0) : destFormat(nullptr),
outputPitch(0),
packBuffer(nullptr),
offset(0),
orientation(SurfaceRotationType::Identity)
{} {}
PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
...@@ -223,7 +226,8 @@ PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, ...@@ -223,7 +226,8 @@ PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
outputPitch(outputPitchIn), outputPitch(outputPitchIn),
packBuffer(packBufferIn), packBuffer(packBufferIn),
reverseRowOrder(reverseRowOrderIn), reverseRowOrder(reverseRowOrderIn),
offset(offsetIn) offset(offsetIn),
orientation(SurfaceRotationType::Identity)
{} {}
void PackPixels(const PackPixelsParams &params, void PackPixels(const PackPixelsParams &params,
...@@ -236,14 +240,73 @@ void PackPixels(const PackPixelsParams &params, ...@@ -236,14 +240,73 @@ void PackPixels(const PackPixelsParams &params,
const uint8_t *source = sourceIn; const uint8_t *source = sourceIn;
int inputPitch = inputPitchIn; int inputPitch = inputPitchIn;
int destWidth = params.area.width;
if (params.reverseRowOrder) int destHeight = params.area.height;
{ int xAxisPitch = 0;
source += inputPitch * (params.area.height - 1); int yAxisPitch = 0;
inputPitch = -inputPitch; switch (params.orientation)
{
case SurfaceRotationType::Identity:
// The source image is not rotated (i.e. matches the device's orientation), and may or
// may not be y-flipped. The image is row-major. Each source row (one step along the
// y-axis for each step in the dest y-axis) is inputPitch past the previous row. Along
// a row, each source pixel (one step along the x-axis for each step in the dest
// x-axis) is sourceFormat.pixelBytes past the previous pixel.
xAxisPitch = sourceFormat.pixelBytes;
if (params.reverseRowOrder)
{
// The source image is y-flipped, which means we start at the last row, and each
// source row is BEFORE the previous row.
source += inputPitchIn * (params.area.height - 1);
inputPitch = -inputPitch;
yAxisPitch = -inputPitchIn;
}
else
{
yAxisPitch = inputPitchIn;
}
break;
case SurfaceRotationType::Rotated90Degrees:
// The source image is rotated 90 degrees counter-clockwise. Y-flip is always applied
// to rotated images. The image is column-major. Each source column (one step along
// the source x-axis for each step in the dest y-axis) is inputPitch past the previous
// column. Along a column, each source pixel (one step along the y-axis for each step
// in the dest x-axis) is sourceFormat.pixelBytes past the previous pixel.
xAxisPitch = inputPitchIn;
yAxisPitch = sourceFormat.pixelBytes;
destWidth = params.area.height;
destHeight = params.area.width;
break;
case SurfaceRotationType::Rotated180Degrees:
// The source image is rotated 180 degrees. Y-flip is always applied to rotated
// images. The image is row-major, but upside down. Each source row (one step along
// the y-axis for each step in the dest y-axis) is inputPitch after the previous row.
// Along a row, each source pixel (one step along the x-axis for each step in the dest
// x-axis) is sourceFormat.pixelBytes BEFORE the previous pixel.
xAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
yAxisPitch = inputPitchIn;
source += sourceFormat.pixelBytes * (params.area.width - 1);
break;
case SurfaceRotationType::Rotated270Degrees:
// The source image is rotated 270 degrees counter-clockwise (or 90 degrees clockwise).
// Y-flip is always applied to rotated images. The image is column-major, where each
// column (one step in the source x-axis for one step in the dest y-axis) is inputPitch
// BEFORE the previous column. Along a column, each source pixel (one step along the
// y-axis for each step in the dest x-axis) is sourceFormat.pixelBytes BEFORE the
// previous pixel. The first pixel is at the end of the source.
xAxisPitch = -inputPitchIn;
yAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
destWidth = params.area.height;
destHeight = params.area.width;
source += inputPitch * (params.area.height - 1) +
sourceFormat.pixelBytes * (params.area.width - 1);
break;
default:
UNREACHABLE();
break;
} }
if (sourceFormat == *params.destFormat) if (params.orientation == SurfaceRotationType::Identity && sourceFormat == *params.destFormat)
{ {
// Direct copy possible // Direct copy possible
for (int y = 0; y < params.area.height; ++y) for (int y = 0; y < params.area.height; ++y)
...@@ -259,13 +322,13 @@ void PackPixels(const PackPixelsParams &params, ...@@ -259,13 +322,13 @@ void PackPixels(const PackPixelsParams &params,
if (fastCopyFunc) if (fastCopyFunc)
{ {
// Fast copy is possible through some special function // Fast copy is possible through some special function
for (int y = 0; y < params.area.height; ++y) for (int y = 0; y < destHeight; ++y)
{ {
for (int x = 0; x < params.area.width; ++x) for (int x = 0; x < destWidth; ++x)
{ {
uint8_t *dest = uint8_t *dest =
destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes; destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
const uint8_t *src = source + y * inputPitch + x * sourceFormat.pixelBytes; const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch;
fastCopyFunc(src, dest); fastCopyFunc(src, dest);
} }
...@@ -286,13 +349,13 @@ void PackPixels(const PackPixelsParams &params, ...@@ -286,13 +349,13 @@ void PackPixels(const PackPixelsParams &params,
PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction; PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction;
ASSERT(pixelReadFunction != nullptr); ASSERT(pixelReadFunction != nullptr);
for (int y = 0; y < params.area.height; ++y) for (int y = 0; y < destHeight; ++y)
{ {
for (int x = 0; x < params.area.width; ++x) for (int x = 0; x < destWidth; ++x)
{ {
uint8_t *dest = uint8_t *dest =
destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes; destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
const uint8_t *src = source + y * inputPitch + x * sourceFormat.pixelBytes; const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch;
// readFunc and writeFunc will be using the same type of color, CopyTexImage // readFunc and writeFunc will be using the same type of color, CopyTexImage
// will not allow the copy otherwise. // will not allow the copy otherwise.
......
...@@ -43,6 +43,23 @@ namespace rx ...@@ -43,6 +43,23 @@ namespace rx
{ {
class ContextImpl; class ContextImpl;
// The possible rotations of the surface/draw framebuffer, particularly for the Vulkan back-end on
// Android.
enum class SurfaceRotationType
{
Identity,
Rotated90Degrees,
Rotated180Degrees,
Rotated270Degrees,
FlippedIdentity,
FlippedRotated90Degrees,
FlippedRotated180Degrees,
FlippedRotated270Degrees,
InvalidEnum,
EnumCount = InvalidEnum,
};
using MipGenerationFunction = void (*)(size_t sourceWidth, using MipGenerationFunction = void (*)(size_t sourceWidth,
size_t sourceHeight, size_t sourceHeight,
size_t sourceDepth, size_t sourceDepth,
...@@ -94,6 +111,7 @@ struct PackPixelsParams ...@@ -94,6 +111,7 @@ struct PackPixelsParams
gl::Buffer *packBuffer; gl::Buffer *packBuffer;
bool reverseRowOrder; bool reverseRowOrder;
ptrdiff_t offset; ptrdiff_t offset;
SurfaceRotationType orientation;
}; };
void PackPixels(const PackPixelsParams &params, void PackPixels(const PackPixelsParams &params,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "common/PackedEnums.h" #include "common/PackedEnums.h"
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/OverlayVk.h" #include "libANGLE/renderer/vulkan/OverlayVk.h"
#include "libANGLE/renderer/vulkan/PersistentCommandPool.h" #include "libANGLE/renderer/vulkan/PersistentCommandPool.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
...@@ -29,23 +30,6 @@ class ProgramExecutableVk; ...@@ -29,23 +30,6 @@ class ProgramExecutableVk;
class RendererVk; class RendererVk;
class WindowSurfaceVk; class WindowSurfaceVk;
// The possible rotations of the surface/draw framebuffer, used for pre-rotating gl_Position
// in the vertex shader.
enum class SurfaceRotationType
{
Identity,
Rotated90Degrees,
Rotated180Degrees,
Rotated270Degrees,
FlippedIdentity,
FlippedRotated90Degrees,
FlippedRotated180Degrees,
FlippedRotated270Degrees,
InvalidEnum,
EnumCount = InvalidEnum,
};
struct CommandBatch final : angle::NonCopyable struct CommandBatch final : angle::NonCopyable
{ {
CommandBatch(); CommandBatch();
......
...@@ -463,9 +463,42 @@ angle::Result FramebufferVk::readPixels(const gl::Context *context, ...@@ -463,9 +463,42 @@ angle::Result FramebufferVk::readPixels(const gl::Context *context,
format, type, area, clippedArea, &params, format, type, area, clippedArea, &params,
&outputSkipBytes)); &outputSkipBytes));
if (contextVk->isViewportFlipEnabledForReadFBO()) bool flipY = contextVk->isViewportFlipEnabledForReadFBO();
switch (params.orientation = contextVk->getRotationReadFramebuffer())
{
case SurfaceRotationType::Identity:
// Do not rotate gl_Position (surface matches the device's orientation):
if (flipY)
{
params.area.y = fbRect.height - clippedArea.y - clippedArea.height;
}
break;
case SurfaceRotationType::Rotated90Degrees:
// Rotate gl_Position 90 degrees:
params.area.x = clippedArea.y;
params.area.y =
flipY ? clippedArea.x : fbRect.width - clippedArea.x - clippedArea.width;
std::swap(params.area.width, params.area.height);
break;
case SurfaceRotationType::Rotated180Degrees:
// Rotate gl_Position 180 degrees:
params.area.x = fbRect.width - clippedArea.x - clippedArea.width;
params.area.y =
flipY ? clippedArea.y : fbRect.height - clippedArea.y - clippedArea.height;
break;
case SurfaceRotationType::Rotated270Degrees:
// Rotate gl_Position 270 degrees:
params.area.x = fbRect.height - clippedArea.y - clippedArea.height;
params.area.y =
flipY ? fbRect.width - clippedArea.x - clippedArea.width : clippedArea.x;
std::swap(params.area.width, params.area.height);
break;
default:
UNREACHABLE();
break;
}
if (flipY)
{ {
params.area.y = fbRect.height - clippedArea.y - clippedArea.height;
params.reverseRowOrder = !params.reverseRowOrder; params.reverseRowOrder = !params.reverseRowOrder;
} }
......
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