Commit 5e424fae by Martin Radev Committed by Commit Bot

Handle Clear* commands for layered framebuffers

The patch adds support for clearing the layers of 2D array textures attached to a multi-view framebuffer. According to the ANGLE_multiview spec, the layers which are outside of the range [baseViewIndex; baseViewIndex + numViews) should remain unmodified. Because the native Clear* commands clear all of the layers, a workaround is implemented which creates a FBO, attaches a single layer from all multi-view attachments and clears the contents. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: Ibf711d02046233eed16bdd3f9c96fc38f82ed0a8 Reviewed-on: https://chromium-review.googlesource.com/615242 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 61bd9994
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ClearMultiviewGL:
// A helper for clearing multiview side-by-side and layered framebuffers.
//
#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/Framebuffer.h"
namespace rx
{
ClearMultiviewGL::ClearMultiviewGL(const FunctionsGL *functions, StateManagerGL *stateManager)
: mFunctions(functions), mStateManager(stateManager), mFramebuffer(0u)
{
}
ClearMultiviewGL::~ClearMultiviewGL()
{
if (mFramebuffer != 0u)
{
mFunctions->deleteFramebuffers(1, &mFramebuffer);
}
}
void ClearMultiviewGL::clearMultiviewFBO(const gl::FramebufferState &state,
const gl::Rectangle &scissorBase,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil)
{
const auto &firstAttachment = state.getFirstNonNullAttachment();
switch (firstAttachment->getMultiviewLayout())
{
case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
clearLayeredFBO(state, clearCommandType, mask, buffer, drawbuffer, values, depth,
stencil);
break;
case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
clearSideBySideFBO(state, scissorBase, clearCommandType, mask, buffer, drawbuffer,
values, depth, stencil);
break;
default:
UNREACHABLE();
}
}
void ClearMultiviewGL::clearLayeredFBO(const gl::FramebufferState &state,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil)
{
initializeResources();
mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer);
const auto &firstAttachment = state.getFirstNonNullAttachment();
ASSERT(firstAttachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE);
const auto &drawBuffers = state.getDrawBufferStates();
mFunctions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data());
// Attach the new attachments and clear.
int numViews = firstAttachment->getNumViews();
int baseViewIndex = firstAttachment->getBaseViewIndex();
for (int i = 0; i < numViews; ++i)
{
attachTextures(state, baseViewIndex + i);
genericClear(clearCommandType, mask, buffer, drawbuffer, values, depth, stencil);
}
detachTextures(state);
}
void ClearMultiviewGL::clearSideBySideFBO(const gl::FramebufferState &state,
const gl::Rectangle &scissorBase,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil)
{
const auto &firstAttachment = state.getFirstNonNullAttachment();
ASSERT(firstAttachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
const auto &viewportOffsets = firstAttachment->getMultiviewViewportOffsets();
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
gl::Rectangle scissor(scissorBase.x + viewportOffsets[i].x,
scissorBase.y + viewportOffsets[i].y, scissorBase.width,
scissorBase.height);
mStateManager->setScissorIndexed(0u, scissor);
genericClear(clearCommandType, mask, buffer, drawbuffer, values, depth, stencil);
}
}
void ClearMultiviewGL::genericClear(ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil)
{
switch (clearCommandType)
{
case ClearCommandType::Clear:
mFunctions->clear(mask);
break;
case ClearCommandType::ClearBufferfv:
mFunctions->clearBufferfv(buffer, drawbuffer,
reinterpret_cast<const GLfloat *>(values));
break;
case ClearCommandType::ClearBufferuiv:
mFunctions->clearBufferuiv(buffer, drawbuffer,
reinterpret_cast<const GLuint *>(values));
break;
case ClearCommandType::ClearBufferiv:
mFunctions->clearBufferiv(buffer, drawbuffer, reinterpret_cast<const GLint *>(values));
break;
case ClearCommandType::ClearBufferfi:
mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
break;
default:
UNREACHABLE();
}
}
void ClearMultiviewGL::attachTextures(const gl::FramebufferState &state, int layer)
{
for (auto drawBufferId : state.getEnabledDrawBuffers())
{
const auto &attachment = state.getColorAttachment(drawBufferId);
if (attachment == nullptr)
{
continue;
}
const auto &imageIndex = attachment->getTextureImageIndex();
ASSERT(imageIndex.type == GL_TEXTURE_2D_ARRAY);
GLenum colorAttachment =
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + static_cast<int>(drawBufferId));
const TextureGL *textureGL = GetImplAs<TextureGL>(attachment->getTexture());
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, colorAttachment,
textureGL->getTextureID(), imageIndex.mipIndex, layer);
}
const auto &depthStencilAttachment = state.getDepthStencilAttachment();
const auto &depthAttachment = state.getDepthAttachment();
const auto &stencilAttachment = state.getStencilAttachment();
if (depthStencilAttachment != nullptr)
{
const auto &imageIndex = depthStencilAttachment->getTextureImageIndex();
ASSERT(imageIndex.type == GL_TEXTURE_2D_ARRAY);
const TextureGL *textureGL = GetImplAs<TextureGL>(depthStencilAttachment->getTexture());
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
textureGL->getTextureID(), imageIndex.mipIndex, layer);
}
else if (depthAttachment != nullptr)
{
const auto &imageIndex = depthAttachment->getTextureImageIndex();
ASSERT(imageIndex.type == GL_TEXTURE_2D_ARRAY);
const TextureGL *textureGL = GetImplAs<TextureGL>(depthAttachment->getTexture());
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
textureGL->getTextureID(), imageIndex.mipIndex, layer);
}
else if (stencilAttachment != nullptr)
{
const auto &imageIndex = stencilAttachment->getTextureImageIndex();
ASSERT(imageIndex.type == GL_TEXTURE_2D_ARRAY);
const TextureGL *textureGL = GetImplAs<TextureGL>(stencilAttachment->getTexture());
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
textureGL->getTextureID(), imageIndex.mipIndex, layer);
}
}
void ClearMultiviewGL::detachTextures(const gl::FramebufferState &state)
{
for (auto drawBufferId : state.getEnabledDrawBuffers())
{
const auto &attachment = state.getColorAttachment(drawBufferId);
if (attachment == nullptr)
{
continue;
}
GLenum colorAttachment =
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + static_cast<int>(drawBufferId));
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, colorAttachment, 0, 0, 0);
}
const auto &depthStencilAttachment = state.getDepthStencilAttachment();
const auto &depthAttachment = state.getDepthAttachment();
const auto &stencilAttachment = state.getStencilAttachment();
if (depthStencilAttachment != nullptr)
{
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0,
0);
}
else if (depthAttachment != nullptr)
{
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0, 0);
}
else if (stencilAttachment != nullptr)
{
mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 0, 0, 0);
}
}
void ClearMultiviewGL::initializeResources()
{
if (mFramebuffer == 0u)
{
mFunctions->genFramebuffers(1, &mFramebuffer);
}
ASSERT(mFramebuffer != 0u);
}
} // namespace rx
\ No newline at end of file
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ClearMultiviewGL:
// A helper for clearing multiview side-by-side and layered framebuffers.
//
#ifndef LIBANGLE_RENDERER_GL_CLEARMULTIVIEWGL_H_
#define LIBANGLE_RENDERER_GL_CLEARMULTIVIEWGL_H_
#include "angle_gl.h"
#include "libANGLE/Error.h"
#include "libANGLE/angletypes.h"
namespace gl
{
class FramebufferState;
} // namespace gl
namespace rx
{
class FunctionsGL;
class StateManagerGL;
class ClearMultiviewGL : angle::NonCopyable
{
public:
// Enum containing the different types of Clear* commands.
enum class ClearCommandType
{
Clear,
ClearBufferfv,
ClearBufferuiv,
ClearBufferiv,
ClearBufferfi
};
public:
ClearMultiviewGL(const FunctionsGL *functions, StateManagerGL *stateManager);
~ClearMultiviewGL();
ClearMultiviewGL(const ClearMultiviewGL &rht) = delete;
ClearMultiviewGL &operator=(const ClearMultiviewGL &rht) = delete;
ClearMultiviewGL(ClearMultiviewGL &&rht) = delete;
ClearMultiviewGL &operator=(ClearMultiviewGL &&rht) = delete;
void clearMultiviewFBO(const gl::FramebufferState &state,
const gl::Rectangle &scissorBase,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil);
void initializeResources();
private:
void attachTextures(const gl::FramebufferState &state, int layer);
void detachTextures(const gl::FramebufferState &state);
void clearLayeredFBO(const gl::FramebufferState &state,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil);
void clearSideBySideFBO(const gl::FramebufferState &state,
const gl::Rectangle &scissorBase,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil);
void genericClear(ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil);
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
GLuint mFramebuffer;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_CLEARMULTIVIEWGL_H_
\ No newline at end of file
......@@ -65,7 +65,7 @@ ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
{
return new FramebufferGL(data, getFunctions(), getStateManager(), getWorkaroundsGL(),
mRenderer->getBlitter(), false);
mRenderer->getBlitter(), mRenderer->getMultiviewClearer(), false);
}
TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
......
......@@ -17,6 +17,7 @@
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RenderbufferGL.h"
......@@ -64,9 +65,19 @@ void BindFramebufferAttachment(const FunctionsGL *functions,
else if (texture->getTarget() == GL_TEXTURE_2D_ARRAY ||
texture->getTarget() == GL_TEXTURE_3D)
{
functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint,
textureGL->getTextureID(),
attachment->mipLevel(), attachment->layer());
if (attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
{
ASSERT(functions->framebufferTexture);
functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
textureGL->getTextureID(),
attachment->mipLevel());
}
else
{
functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint,
textureGL->getTextureID(),
attachment->mipLevel(), attachment->layer());
}
}
else
{
......@@ -106,11 +117,26 @@ void RetrieveMultiviewFieldsFromAttachment(const gl::FramebufferAttachment *atta
}
}
bool RequiresMultipleClears(const FramebufferAttachment *attachment, bool scissorTestEnabled)
bool RequiresMultiviewClear(const FramebufferAttachment *attachment, bool scissorTestEnabled)
{
return attachment != nullptr &&
attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE &&
scissorTestEnabled;
if (attachment == nullptr)
{
return false;
}
switch (attachment->getMultiviewLayout())
{
case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
// TODO(mradev): Optimize this for layered FBOs in which all of the layers in each
// attachment are active.
return true;
case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
return (scissorTestEnabled == true);
case GL_NONE:
return false;
default:
UNREACHABLE();
}
return false;
}
} // namespace
......@@ -120,12 +146,14 @@ FramebufferGL::FramebufferGL(const FramebufferState &state,
StateManagerGL *stateManager,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
bool isDefault)
: FramebufferImpl(state),
mFunctions(functions),
mStateManager(stateManager),
mWorkarounds(workarounds),
mBlitter(blitter),
mMultiviewClearer(multiviewClearer),
mFramebufferID(0),
mIsDefault(isDefault),
mAppliedEnabledDrawBuffers(1)
......@@ -141,12 +169,14 @@ FramebufferGL::FramebufferGL(GLuint id,
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
StateManagerGL *stateManager)
: FramebufferImpl(state),
mFunctions(functions),
mStateManager(stateManager),
mWorkarounds(workarounds),
mBlitter(blitter),
mMultiviewClearer(multiviewClearer),
mFramebufferID(id),
mIsDefault(true),
mAppliedEnabledDrawBuffers(1)
......@@ -224,15 +254,16 @@ Error FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
syncClearState(context, mask);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
const auto &firstAttachment = mState.getFirstNonNullAttachment();
if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::Clear, mask, GL_NONE, 0, nullptr, 0.0f,
0);
mFunctions->clear(mask);
}
else
{
mFunctions->clear(mask);
mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::Clear, mask,
GL_NONE, 0, nullptr, 0.0f, 0);
}
return gl::NoError();
......@@ -246,16 +277,17 @@ Error FramebufferGL::clearBufferfv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
const auto &firstAttachment = mState.getFirstNonNullAttachment();
if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferfv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
mFunctions->clearBufferfv(buffer, drawbuffer, values);
}
else
{
mFunctions->clearBufferfv(buffer, drawbuffer, values);
mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::ClearBufferfv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
}
return gl::NoError();
......@@ -269,16 +301,17 @@ Error FramebufferGL::clearBufferuiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
const auto &firstAttachment = mState.getFirstNonNullAttachment();
if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferuiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
mFunctions->clearBufferuiv(buffer, drawbuffer, values);
}
else
{
mFunctions->clearBufferuiv(buffer, drawbuffer, values);
mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::ClearBufferuiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
}
return gl::NoError();
......@@ -292,16 +325,17 @@ Error FramebufferGL::clearBufferiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
const auto &firstAttachment = mState.getFirstNonNullAttachment();
if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
mFunctions->clearBufferiv(buffer, drawbuffer, values);
}
else
{
mFunctions->clearBufferiv(buffer, drawbuffer, values);
mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::ClearBufferiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
}
return gl::NoError();
......@@ -316,70 +350,22 @@ Error FramebufferGL::clearBufferfi(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
const auto &firstAttachment = mState.getFirstNonNullAttachment();
if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferfi,
static_cast<GLbitfield>(0u), buffer, drawbuffer, nullptr, depth,
stencil);
mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
}
else
{
mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::ClearBufferfi,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
nullptr, depth, stencil);
}
return gl::NoError();
}
void FramebufferGL::genericSideBySideClear(const gl::Context *context,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil)
{
// For side-by-side framebuffers we have to go over each view and set its scissor rectangle
// as the first one and just then call Clear*. This is necessary because Clear* commands use
// only the first viewport's scissor rectangle.
const auto &scissorBase = context->getGLState().getScissor();
const FramebufferAttachment *attachment = mState.getFirstNonNullAttachment();
ASSERT(attachment != nullptr);
const auto &viewportOffsets = attachment->getMultiviewViewportOffsets();
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
gl::Rectangle scissor(scissorBase.x + viewportOffsets[i].x,
scissorBase.y + viewportOffsets[i].y, scissorBase.width,
scissorBase.height);
mStateManager->setScissorIndexed(0u, scissor);
switch (clearCommandType)
{
case ClearCommandType::Clear:
mFunctions->clear(mask);
break;
case ClearCommandType::ClearBufferfv:
mFunctions->clearBufferfv(buffer, drawbuffer,
reinterpret_cast<const GLfloat *>(values));
break;
case ClearCommandType::ClearBufferuiv:
mFunctions->clearBufferuiv(buffer, drawbuffer,
reinterpret_cast<const GLuint *>(values));
break;
case ClearCommandType::ClearBufferiv:
mFunctions->clearBufferiv(buffer, drawbuffer,
reinterpret_cast<const GLint *>(values));
break;
case ClearCommandType::ClearBufferfi:
mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
break;
default:
UNREACHABLE();
}
}
}
GLenum FramebufferGL::getImplementationColorReadFormat(const gl::Context *context) const
{
const auto *readAttachment = mState.getReadAttachment();
......@@ -667,6 +653,7 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
}
}
// TODO(mradev): Handle case in which a texture is detached in a multi-view context.
if (isAttachmentModified)
{
const bool isSideBySide = multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
......
......@@ -15,6 +15,7 @@ namespace rx
{
class BlitGL;
class ClearMultiviewGL;
class FunctionsGL;
class StateManagerGL;
struct WorkaroundsGL;
......@@ -27,6 +28,7 @@ class FramebufferGL : public FramebufferImpl
StateManagerGL *stateManager,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
bool isDefault);
// Constructor called when we need to create a FramebufferGL from an
// existing framebuffer name, for example for the default framebuffer
......@@ -36,6 +38,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
StateManagerGL *stateManager);
~FramebufferGL() override;
......@@ -95,17 +98,6 @@ class FramebufferGL : public FramebufferImpl
void maskOutInactiveOutputDrawBuffers(gl::DrawBufferMask maxSet);
private:
// Enum containing the different types of Clear* commands.
enum class ClearCommandType
{
Clear,
ClearBufferfv,
ClearBufferuiv,
ClearBufferiv,
ClearBufferfi
};
private:
void syncClearState(const gl::Context *context, GLbitfield mask);
void syncClearBufferState(const gl::Context *context, GLenum buffer, GLint drawBuffer);
......@@ -129,19 +121,11 @@ class FramebufferGL : public FramebufferImpl
GLubyte *pixels,
bool readLastRowSeparately) const;
void genericSideBySideClear(const gl::Context *context,
ClearCommandType clearCommandType,
GLbitfield mask,
GLenum buffer,
GLint drawbuffer,
const uint8_t *values,
GLfloat depth,
GLint stencil);
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds;
BlitGL *mBlitter;
ClearMultiviewGL *mMultiviewClearer;
GLuint mFramebufferID;
bool mIsDefault;
......
......@@ -18,6 +18,7 @@
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/BufferGL.h"
#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/CompilerGL.h"
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FenceNVGL.h"
......@@ -168,6 +169,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
mFunctions(functions),
mStateManager(nullptr),
mBlitter(nullptr),
mMultiviewClearer(nullptr),
mUseDebugOutput(false),
mSkipDrawCalls(false),
mCapsInitialized(false),
......@@ -177,6 +179,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds);
mStateManager = new StateManagerGL(mFunctions, getNativeCaps(), getNativeExtensions());
mBlitter = new BlitGL(functions, mWorkarounds, mStateManager);
mMultiviewClearer = new ClearMultiviewGL(functions, mStateManager);
bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) ||
mFunctions->hasGLExtension("GL_KHR_debug") ||
......@@ -222,6 +225,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
RendererGL::~RendererGL()
{
SafeDelete(mBlitter);
SafeDelete(mMultiviewClearer);
SafeDelete(mStateManager);
}
......
......@@ -36,6 +36,7 @@ struct BlockMemberInfo;
namespace rx
{
class BlitGL;
class ClearMultiviewGL;
class ContextImpl;
class FunctionsGL;
class StateManagerGL;
......@@ -159,6 +160,7 @@ class RendererGL : angle::NonCopyable
StateManagerGL *getStateManager() const { return mStateManager; }
const WorkaroundsGL &getWorkarounds() const { return mWorkarounds; }
BlitGL *getBlitter() const { return mBlitter; }
ClearMultiviewGL *getMultiviewClearer() const { return mMultiviewClearer; }
MultiviewImplementationTypeGL getMultiviewImplementationType() const;
const gl::Caps &getNativeCaps() const;
......@@ -185,6 +187,7 @@ class RendererGL : angle::NonCopyable
StateManagerGL *mStateManager;
BlitGL *mBlitter;
ClearMultiviewGL *mMultiviewClearer;
WorkaroundsGL mWorkarounds;
......
......@@ -26,7 +26,8 @@ SurfaceGL::~SurfaceGL()
FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{
return new FramebufferGL(data, mRenderer->getFunctions(), mRenderer->getStateManager(),
mRenderer->getWorkarounds(), mRenderer->getBlitter(), true);
mRenderer->getWorkarounds(), mRenderer->getBlitter(),
mRenderer->getMultiviewClearer(), true);
}
egl::Error SurfaceGL::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
......
......@@ -141,7 +141,8 @@ FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::Framebuff
{
// TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mRenderer->getWorkarounds(),
mRenderer->getBlitter(), mStateManager);
mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
}
} // namespace rx
......@@ -330,7 +330,7 @@ FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Framebuffe
{
// TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mRenderer->getBlitter(),
mStateManager);
mRenderer->getMultiviewClearer(), mStateManager);
}
} // namespace rx
......@@ -309,7 +309,8 @@ FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &s
{
return new FramebufferGL(
mGLFB, state, mDisplay->mFunctionsGL, mDisplay->getRenderer()->getWorkarounds(),
mDisplay->getRenderer()->getBlitter(), mDisplay->getRenderer()->getStateManager());
mDisplay->getRenderer()->getBlitter(), mDisplay->getRenderer()->getMultiviewClearer(),
mDisplay->getRenderer()->getStateManager());
}
void DisplayOzone::Buffer::present()
......
......@@ -466,7 +466,8 @@ EGLint D3DTextureSurfaceWGL::getSwapBehavior() const
FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds,
mRenderer->getBlitter(), mStateManager);
mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
}
HDC D3DTextureSurfaceWGL::getDC() const
......
......@@ -270,7 +270,8 @@ FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
const gl::FramebufferState &data)
{
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds,
mRenderer->getBlitter(), mStateManager);
mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
}
HDC DXGISwapChainWindowSurfaceWGL::getDC() const
......
......@@ -559,6 +559,8 @@
'libANGLE/renderer/gl/BlitGL.h',
'libANGLE/renderer/gl/BufferGL.cpp',
'libANGLE/renderer/gl/BufferGL.h',
'libANGLE/renderer/gl/ClearMultiviewGL.cpp',
'libANGLE/renderer/gl/ClearMultiviewGL.h',
'libANGLE/renderer/gl/CompilerGL.cpp',
'libANGLE/renderer/gl/CompilerGL.h',
'libANGLE/renderer/gl/ContextGL.cpp',
......
......@@ -62,10 +62,10 @@ class FramebufferMultiviewTest : public ANGLETest
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
class FramebufferMultiviewSideBySideClearTest : public FramebufferMultiviewTest
{
protected:
FramebufferMultiviewClearTest() {}
FramebufferMultiviewSideBySideClearTest() {}
void initializeFBOs(size_t numColorBuffers, bool stencil, bool depth)
{
......@@ -116,7 +116,7 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
}
glDrawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data());
// Generate normal fbo and attach textures.
// Generate non-multiview fbo and attach textures.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
for (size_t i = 0u; i < numColorBuffers; ++i)
{
......@@ -164,8 +164,118 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
GLTexture mStencilTex;
};
// Test that the framebuffer tokens introduced by ANGLE_multiview can be used query the framebuffer
// state and that their corresponding default values are correctly set.
class FramebufferMultiviewLayeredClearTest : public FramebufferMultiviewTest
{
protected:
FramebufferMultiviewLayeredClearTest() {}
void initializeFBOs(int width,
int height,
int numLayers,
int baseViewIndex,
int numViews,
int numColorAttachments,
bool stencil,
bool depth)
{
ASSERT(baseViewIndex + numViews <= numLayers);
// Generate textures.
mColorTex.resize(numColorAttachments);
for (int i = 0; i < numColorAttachments; ++i)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTex[i]);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, width, height, numLayers, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
}
if (stencil)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, mStencilTex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, width, height, numLayers, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
}
else if (depth)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, width, height, numLayers, 0,
GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
}
// Generate multiview FBO and attach textures.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
for (int i = 0; i < numColorAttachments; ++i)
{
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER,
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i),
mColorTex[i], 0, baseViewIndex, numViews);
}
if (stencil)
{
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
mStencilTex, 0, baseViewIndex, numViews);
}
else if (depth)
{
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
mDepthTex, 0, baseViewIndex, numViews);
}
const auto &drawBuffers = GetDrawBufferRange(numColorAttachments);
glDrawBuffers(numColorAttachments, drawBuffers.data());
// Generate non-multiview FBOs and attach textures.
mNonMultiviewFBO.resize(numLayers);
for (int i = 0; i < numLayers; ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
for (int j = 0; j < numColorAttachments; ++j)
{
glFramebufferTextureLayer(GL_FRAMEBUFFER,
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + j),
mColorTex[j], 0, i);
}
if (stencil)
{
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, mStencilTex,
0, i);
}
else if (depth)
{
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTex, 0, i);
}
glDrawBuffers(numColorAttachments, drawBuffers.data());
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
ASSERT_GL_NO_ERROR();
}
GLColor getLayerColor(size_t layer, GLenum attachment, GLint x, GLint y)
{
ASSERT(layer < mNonMultiviewFBO.size());
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[layer]);
glReadBuffer(attachment);
return angle::ReadColor(x, y);
}
GLColor getLayerColor(size_t layer, GLenum attachment)
{
return getLayerColor(layer, attachment, 0, 0);
}
GLFramebuffer mMultiviewFBO;
std::vector<GLFramebuffer> mNonMultiviewFBO;
std::vector<GLTexture> mColorTex;
GLTexture mDepthTex;
GLTexture mStencilTex;
};
// Test that the framebuffer tokens introduced by ANGLE_multiview can be used to query the
// framebuffer state and that their corresponding default values are correctly set.
TEST_P(FramebufferMultiviewTest, DefaultState)
{
if (!requestMultiviewExtension())
......@@ -588,7 +698,7 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels)
}
// Test that glClear clears only the contents of each view if the scissor test is enabled.
TEST_P(FramebufferMultiviewClearTest, SideBySideColorBufferClear)
TEST_P(FramebufferMultiviewSideBySideClearTest, ColorBufferClear)
{
if (!requestMultiviewExtension())
{
......@@ -707,7 +817,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Test framebuffer completeness when the 1st attachment has a normal layout.
// Test framebuffer completeness when the 1st attachment has a non-multiview layout.
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
......@@ -722,7 +832,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
}
// Test that glClear clears all of the contents if the scissor test is disabled.
TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest)
TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest)
{
if (!requestMultiviewExtension())
{
......@@ -756,7 +866,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest)
}
// Test that glClear clears the depth buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear)
TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear)
{
if (!requestMultiviewExtension())
{
......@@ -812,7 +922,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear)
}
// Test that glClear clears the stencil buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear)
TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear)
{
if (!requestMultiviewExtension())
{
......@@ -876,7 +986,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear)
}
// Test that glClearBufferf clears the color buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF)
TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF)
{
if (!requestMultiviewExtension())
{
......@@ -916,5 +1026,204 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF)
checkAlternatingColumnsOfRedAndGreenInFBO();
}
// Test that glClear clears the contents of the color buffer for only the attached layers to a
// layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear)
{
if (!requestMultiviewExtension())
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 1, false, false);
// Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
}
// Test that glClearBufferfv can be used to clear individual color buffers of a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer)
{
if (!requestMultiviewExtension())
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
for (int i = 0; i < 2; ++i)
{
for (int layer = 0; layer < 4; ++layer)
{
GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
EXPECT_EQ(GLColor::red, getLayerColor(layer, colorAttachment));
}
}
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
float clearValues0[4] = {0.f, 0.f, 1.f, 1.f};
glClearBufferfv(GL_COLOR, 0, clearValues0);
float clearValues1[4] = {0.f, 1.f, 0.f, 1.f};
glClearBufferfv(GL_COLOR, 1, clearValues1);
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::blue, getLayerColor(1, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::blue, getLayerColor(2, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT1));
}
// Test that glClearBufferfi clears the contents of the stencil buffer for only the attached layers
// to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi)
{
if (!requestMultiviewExtension())
{
return;
}
// Create program to draw a quad.
const std::string &vs =
"#version 300 es\n"
"in vec3 vPos;\n"
"void main(){\n"
" gl_Position = vec4(vPos, 1.);\n"
"}\n";
const std::string &fs =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec3 uCol;\n"
"out vec4 col;\n"
"void main(){\n"
" col = vec4(uCol,1.);\n"
"}\n";
ANGLE_GL_PROGRAM(program, vs, fs);
glUseProgram(program);
GLuint mColorUniformLoc = glGetUniformLocation(program, "uCol");
initializeFBOs(1, 1, 4, 1, 2, 1, true, false);
glEnable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
// Set clear values.
glClearColor(1, 0, 0, 1);
glClearStencil(0xFF);
// Clear the color and stencil buffers of each layer.
for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
// Switch to multiview framebuffer and clear portions of the texture.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
// Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
// the test.
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_EQUAL, 0x00, 0xFF);
for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
drawQuad(program, "vPos", 0.0f, 1.0f, true);
}
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
}
// Test that glClear does not clear the content of a detached texture.
TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture)
{
if (!requestMultiviewExtension())
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
// Clear all attachments.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < 2; ++i)
{
GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
EXPECT_EQ(GLColor::red, getLayerColor(0, colorAttachment));
EXPECT_EQ(GLColor::green, getLayerColor(1, colorAttachment));
EXPECT_EQ(GLColor::green, getLayerColor(2, colorAttachment));
EXPECT_EQ(GLColor::red, getLayerColor(3, colorAttachment));
}
// Detach and clear again.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0, 0, 1, 2);
glClearColor(1, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
// Check that color attachment 0 is modified.
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::yellow, getLayerColor(1, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::yellow, getLayerColor(2, GL_COLOR_ATTACHMENT0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
// Check that color attachment 1 is unmodified.
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT1));
}
// Test that glClear clears only the contents within the scissor rectangle of the attached layers.
TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear)
{
if (!requestMultiviewExtension())
{
return;
}
initializeFBOs(2, 1, 4, 1, 2, 1, false, false);
// Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glEnable(GL_SCISSOR_TEST);
glScissor(1, 0, 1, 1);
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 0));
EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 1, 0));
EXPECT_EQ(GLColor::red, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 0));
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0, 1, 0));
EXPECT_EQ(GLColor::red, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 0));
EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0, 1, 0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 0));
EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 1, 0));
}
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewClearTest, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewSideBySideClearTest, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewLayeredClearTest, ES3_OPENGL());
\ No newline at end of file
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