Commit 47155b17 by Olli Etuaho Committed by Commit Bot

Clean up BlitGL

Simplify handling of reversing the blitted area and calculate shader parameters in a way that doesn't require lengthy explanation. BUG=chromium:830046 TEST=angle_end2end_tests Change-Id: Ie9bce812be4ef04a969153fc7c484039fc48a198 Reviewed-on: https://chromium-review.googlesource.com/1030172 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 57d9cbb6
...@@ -190,6 +190,22 @@ static void MinMax(int a, int b, int *minimum, int *maximum) ...@@ -190,6 +190,22 @@ static void MinMax(int a, int b, int *minimum, int *maximum)
} }
} }
Rectangle Rectangle::removeReversal() const
{
Rectangle unreversed = *this;
if (isReversedX())
{
unreversed.x = unreversed.x + unreversed.width;
unreversed.width = -unreversed.width;
}
if (isReversedY())
{
unreversed.y = unreversed.y + unreversed.height;
unreversed.height = -unreversed.height;
}
return unreversed;
}
bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection)
{ {
int minSourceX, maxSourceX, minSourceY, maxSourceY; int minSourceX, maxSourceX, minSourceY, maxSourceY;
......
...@@ -55,6 +55,12 @@ struct Rectangle ...@@ -55,6 +55,12 @@ struct Rectangle
int x1() const { return x + width; } int x1() const { return x + width; }
int y1() const { return y + height; } int y1() const { return y + height; }
bool isReversedX() const { return width < 0; }
bool isReversedY() const { return height < 0; }
// Returns a rectangle with the same area but with height and width guaranteed to be positive.
Rectangle removeReversal() const;
int x; int x;
int y; int y;
int width; int width;
......
...@@ -370,24 +370,13 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source, ...@@ -370,24 +370,13 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source,
BlitProgram *blitProgram = nullptr; BlitProgram *blitProgram = nullptr;
ANGLE_TRY(getBlitProgram(BlitProgramType::FLOAT_TO_FLOAT, &blitProgram)); ANGLE_TRY(getBlitProgram(BlitProgramType::FLOAT_TO_FLOAT, &blitProgram));
// Normalize the destination area to have positive width and height because we will use // We'll keep things simple by removing reversed coordinates from the rectangles. In the end
// glViewport to set it, which doesn't allow negative width or height. // we'll apply the reversal to the source texture coordinates if needed. The destination
gl::Rectangle sourceArea = sourceAreaIn; // rectangle will be set to the gl viewport, which can't be reversed.
gl::Rectangle destArea = destAreaIn; bool reverseX = sourceAreaIn.isReversedX() != destAreaIn.isReversedX();
if (destArea.width < 0) bool reverseY = sourceAreaIn.isReversedY() != destAreaIn.isReversedY();
{ gl::Rectangle sourceArea = sourceAreaIn.removeReversal();
destArea.x += destArea.width; gl::Rectangle destArea = destAreaIn.removeReversal();
destArea.width = -destArea.width;
sourceArea.x += sourceArea.width;
sourceArea.width = -sourceArea.width;
}
if (destArea.height < 0)
{
destArea.y += destArea.height;
destArea.height = -destArea.height;
sourceArea.y += sourceArea.height;
sourceArea.height = -sourceArea.height;
}
const gl::FramebufferAttachment *readAttachment = source->getReadColorbuffer(); const gl::FramebufferAttachment *readAttachment = source->getReadColorbuffer();
ASSERT(readAttachment->getSamples() <= 1); ASSERT(readAttachment->getSamples() <= 1);
...@@ -397,57 +386,23 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source, ...@@ -397,57 +386,23 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source,
{ {
gl::Extents sourceSize = readAttachment->getSize(); gl::Extents sourceSize = readAttachment->getSize();
gl::Rectangle sourceBounds(0, 0, sourceSize.width, sourceSize.height); gl::Rectangle sourceBounds(0, 0, sourceSize.width, sourceSize.height);
gl::ClipRectangle(sourceArea, sourceBounds, &inBoundsSource); if (!gl::ClipRectangle(sourceArea, sourceBounds, &inBoundsSource))
// Note that inBoundsSource will have lost the orientation information.
ASSERT(inBoundsSource.width >= 0 && inBoundsSource.height >= 0);
// Early out when the sampled part is empty as the blit will be a noop,
// and it prevents a division by zero in later computations.
if (inBoundsSource.width == 0 || inBoundsSource.height == 0)
{ {
// Early out when the sampled part is empty as the blit will be a noop,
// and it prevents a division by zero in later computations.
return gl::NoError(); return gl::NoError();
} }
} }
// The blit will be emulated by getting the source of the blit in a texture and sampling it // The blit will be emulated by getting the source of the blit in a texture and sampling it
// with CLAMP_TO_EDGE. The quad used to draw can trivially compute texture coordinates going // with CLAMP_TO_EDGE.
// from (0, 0) to (1, 1). These texture coordinates will need to be transformed to make two
// regions match:
// - The region of the texture representing the source framebuffer region that will be sampled
// - The region of the drawn quad that corresponds to non-clamped blit, this is the same as the
// region of the source rectangle that is inside the source attachment.
//
// These two regions, T (texture) and D (dest) are defined by their offset in texcoord space
// in (0, 1)^2 and their size in texcoord space in (-1, 1)^2. The size can be negative to
// represent the orientation of the blit.
//
// Then if P is the quad texcoord, Q the texcoord inside T, and R the texture texcoord:
// - Q = (P - D.offset) / D.size
// - Q = (R - T.offset) / T.size
// Hence R = (P - D.offset) / D.size * T.size - T.offset
// = P * (T.size / D.size) + (T.offset - D.offset * T.size / D.size)
GLuint textureId; GLuint textureId;
Vector2 TOffset;
Vector2 TSize;
// TODO(cwallez) once texture dirty bits are landed, reuse attached texture instead of using // TODO(cwallez) once texture dirty bits are landed, reuse attached texture instead of using
// CopyTexImage2D // CopyTexImage2D
{ {
textureId = mScratchTextures[0]; textureId = mScratchTextures[0];
TOffset = Vector2(0.0);
TSize = Vector2(1.0);
if (sourceArea.width < 0)
{
TOffset.x() = 1.0;
TSize.x() = -1.0;
}
if (sourceArea.height < 0)
{
TOffset.y() = 1.0;
TSize.y() = -1.0;
}
GLenum format = readAttachment->getFormat().info->internalFormat; GLenum format = readAttachment->getFormat().info->internalFormat;
const FramebufferGL *sourceGL = GetImplAs<FramebufferGL>(source); const FramebufferGL *sourceGL = GetImplAs<FramebufferGL>(source);
...@@ -457,40 +412,36 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source, ...@@ -457,40 +412,36 @@ gl::Error BlitGL::blitColorBufferWithShader(const gl::Framebuffer *source,
mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, format, inBoundsSource.x, inBoundsSource.y, mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, format, inBoundsSource.x, inBoundsSource.y,
inBoundsSource.width, inBoundsSource.height, 0); inBoundsSource.width, inBoundsSource.height, 0);
// Translate sourceArea to be relative to the copied image.
sourceArea.x -= inBoundsSource.x;
sourceArea.y -= inBoundsSource.y;
setScratchTextureParameter(GL_TEXTURE_MIN_FILTER, filter); setScratchTextureParameter(GL_TEXTURE_MIN_FILTER, filter);
setScratchTextureParameter(GL_TEXTURE_MAG_FILTER, filter); setScratchTextureParameter(GL_TEXTURE_MAG_FILTER, filter);
setScratchTextureParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); setScratchTextureParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
setScratchTextureParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); setScratchTextureParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
// Compute normalized sampled draw quad region // Transform the source area to the texture coordinate space (where 0.0 and 1.0 correspond to
// It is the same as the region of the source rectangle that is in bounds. // the edges of the texture).
Vector2 DOffset; Vector2 texCoordOffset(
Vector2 DSize; static_cast<float>(sourceArea.x) / static_cast<float>(inBoundsSource.width),
static_cast<float>(sourceArea.y) / static_cast<float>(inBoundsSource.height));
// texCoordScale is equal to the size of the source area in texture coordinates.
Vector2 texCoordScale(
static_cast<float>(sourceArea.width) / static_cast<float>(inBoundsSource.width),
static_cast<float>(sourceArea.height) / static_cast<float>(inBoundsSource.height));
if (reverseX)
{ {
ASSERT(sourceArea.width != 0 && sourceArea.height != 0); texCoordOffset.x() = texCoordOffset.x() + texCoordScale.x();
gl::Rectangle orientedInBounds = inBoundsSource; texCoordScale.x() = -texCoordScale.x();
if (sourceArea.width < 0) }
{ if (reverseY)
orientedInBounds.x += orientedInBounds.width; {
orientedInBounds.width = -orientedInBounds.width; texCoordOffset.y() = texCoordOffset.y() + texCoordScale.y();
} texCoordScale.y() = -texCoordScale.y();
if (sourceArea.height < 0)
{
orientedInBounds.y += orientedInBounds.height;
orientedInBounds.height = -orientedInBounds.height;
}
DOffset =
Vector2(static_cast<float>(orientedInBounds.x - sourceArea.x) / sourceArea.width,
static_cast<float>(orientedInBounds.y - sourceArea.y) / sourceArea.height);
DSize = Vector2(static_cast<float>(orientedInBounds.width) / sourceArea.width,
static_cast<float>(orientedInBounds.height) / sourceArea.height);
} }
ASSERT(DSize.x() != 0.0 && DSize.y() != 0.0);
Vector2 texCoordScale = TSize / DSize;
Vector2 texCoordOffset = TOffset - DOffset * texCoordScale;
// Reset all the state except scissor and use the viewport to draw exactly to the destination // Reset all the state except scissor and use the viewport to draw exactly to the destination
// rectangle // rectangle
......
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