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) ...@@ -65,7 +65,7 @@ ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data) FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
{ {
return new FramebufferGL(data, getFunctions(), getStateManager(), getWorkaroundsGL(), return new FramebufferGL(data, getFunctions(), getStateManager(), getWorkaroundsGL(),
mRenderer->getBlitter(), false); mRenderer->getBlitter(), mRenderer->getMultiviewClearer(), false);
} }
TextureImpl *ContextGL::createTexture(const gl::TextureState &state) TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/gl/BlitGL.h" #include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/ContextGL.h" #include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RenderbufferGL.h" #include "libANGLE/renderer/gl/RenderbufferGL.h"
...@@ -64,9 +65,19 @@ void BindFramebufferAttachment(const FunctionsGL *functions, ...@@ -64,9 +65,19 @@ void BindFramebufferAttachment(const FunctionsGL *functions,
else if (texture->getTarget() == GL_TEXTURE_2D_ARRAY || else if (texture->getTarget() == GL_TEXTURE_2D_ARRAY ||
texture->getTarget() == GL_TEXTURE_3D) texture->getTarget() == GL_TEXTURE_3D)
{ {
functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint, if (attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
textureGL->getTextureID(), {
attachment->mipLevel(), attachment->layer()); 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 else
{ {
...@@ -106,11 +117,26 @@ void RetrieveMultiviewFieldsFromAttachment(const gl::FramebufferAttachment *atta ...@@ -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 && if (attachment == nullptr)
attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE && {
scissorTestEnabled; 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 } // namespace
...@@ -120,12 +146,14 @@ FramebufferGL::FramebufferGL(const FramebufferState &state, ...@@ -120,12 +146,14 @@ FramebufferGL::FramebufferGL(const FramebufferState &state,
StateManagerGL *stateManager, StateManagerGL *stateManager,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter, BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
bool isDefault) bool isDefault)
: FramebufferImpl(state), : FramebufferImpl(state),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mWorkarounds(workarounds), mWorkarounds(workarounds),
mBlitter(blitter), mBlitter(blitter),
mMultiviewClearer(multiviewClearer),
mFramebufferID(0), mFramebufferID(0),
mIsDefault(isDefault), mIsDefault(isDefault),
mAppliedEnabledDrawBuffers(1) mAppliedEnabledDrawBuffers(1)
...@@ -141,12 +169,14 @@ FramebufferGL::FramebufferGL(GLuint id, ...@@ -141,12 +169,14 @@ FramebufferGL::FramebufferGL(GLuint id,
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter, BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
StateManagerGL *stateManager) StateManagerGL *stateManager)
: FramebufferImpl(state), : FramebufferImpl(state),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mWorkarounds(workarounds), mWorkarounds(workarounds),
mBlitter(blitter), mBlitter(blitter),
mMultiviewClearer(multiviewClearer),
mFramebufferID(id), mFramebufferID(id),
mIsDefault(true), mIsDefault(true),
mAppliedEnabledDrawBuffers(1) mAppliedEnabledDrawBuffers(1)
...@@ -224,15 +254,16 @@ Error FramebufferGL::clear(const gl::Context *context, GLbitfield mask) ...@@ -224,15 +254,16 @@ Error FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
syncClearState(context, mask); syncClearState(context, mask);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(), const auto &firstAttachment = mState.getFirstNonNullAttachment();
context->getGLState().isScissorTestEnabled())) if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{ {
genericSideBySideClear(context, ClearCommandType::Clear, mask, GL_NONE, 0, nullptr, 0.0f, mFunctions->clear(mask);
0);
} }
else else
{ {
mFunctions->clear(mask); mMultiviewClearer->clearMultiviewFBO(mState, context->getGLState().getScissor(),
ClearMultiviewGL::ClearCommandType::Clear, mask,
GL_NONE, 0, nullptr, 0.0f, 0);
} }
return gl::NoError(); return gl::NoError();
...@@ -246,16 +277,17 @@ Error FramebufferGL::clearBufferfv(const gl::Context *context, ...@@ -246,16 +277,17 @@ Error FramebufferGL::clearBufferfv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer); syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(), const auto &firstAttachment = mState.getFirstNonNullAttachment();
context->getGLState().isScissorTestEnabled())) if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{ {
genericSideBySideClear(context, ClearCommandType::ClearBufferfv, mFunctions->clearBufferfv(buffer, drawbuffer, values);
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
} }
else 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(); return gl::NoError();
...@@ -269,16 +301,17 @@ Error FramebufferGL::clearBufferuiv(const gl::Context *context, ...@@ -269,16 +301,17 @@ Error FramebufferGL::clearBufferuiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer); syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(), const auto &firstAttachment = mState.getFirstNonNullAttachment();
context->getGLState().isScissorTestEnabled())) if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{ {
genericSideBySideClear(context, ClearCommandType::ClearBufferuiv, mFunctions->clearBufferuiv(buffer, drawbuffer, values);
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
} }
else 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(); return gl::NoError();
...@@ -292,16 +325,17 @@ Error FramebufferGL::clearBufferiv(const gl::Context *context, ...@@ -292,16 +325,17 @@ Error FramebufferGL::clearBufferiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer); syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(), const auto &firstAttachment = mState.getFirstNonNullAttachment();
context->getGLState().isScissorTestEnabled())) if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{ {
genericSideBySideClear(context, ClearCommandType::ClearBufferiv, mFunctions->clearBufferiv(buffer, drawbuffer, values);
static_cast<GLbitfield>(0u), buffer, drawbuffer,
reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
} }
else 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(); return gl::NoError();
...@@ -316,70 +350,22 @@ Error FramebufferGL::clearBufferfi(const gl::Context *context, ...@@ -316,70 +350,22 @@ Error FramebufferGL::clearBufferfi(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer); syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(), const auto &firstAttachment = mState.getFirstNonNullAttachment();
context->getGLState().isScissorTestEnabled())) if (!RequiresMultiviewClear(firstAttachment, context->getGLState().isScissorTestEnabled()))
{ {
genericSideBySideClear(context, ClearCommandType::ClearBufferfi, mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil);
static_cast<GLbitfield>(0u), buffer, drawbuffer, nullptr, depth,
stencil);
} }
else 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(); 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 GLenum FramebufferGL::getImplementationColorReadFormat(const gl::Context *context) const
{ {
const auto *readAttachment = mState.getReadAttachment(); const auto *readAttachment = mState.getReadAttachment();
...@@ -667,6 +653,7 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir ...@@ -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) if (isAttachmentModified)
{ {
const bool isSideBySide = multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE; const bool isSideBySide = multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
......
...@@ -15,6 +15,7 @@ namespace rx ...@@ -15,6 +15,7 @@ namespace rx
{ {
class BlitGL; class BlitGL;
class ClearMultiviewGL;
class FunctionsGL; class FunctionsGL;
class StateManagerGL; class StateManagerGL;
struct WorkaroundsGL; struct WorkaroundsGL;
...@@ -27,6 +28,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -27,6 +28,7 @@ class FramebufferGL : public FramebufferImpl
StateManagerGL *stateManager, StateManagerGL *stateManager,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter, BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
bool isDefault); bool isDefault);
// Constructor called when we need to create a FramebufferGL from an // Constructor called when we need to create a FramebufferGL from an
// existing framebuffer name, for example for the default framebuffer // existing framebuffer name, for example for the default framebuffer
...@@ -36,6 +38,7 @@ class FramebufferGL : public FramebufferImpl ...@@ -36,6 +38,7 @@ class FramebufferGL : public FramebufferImpl
const FunctionsGL *functions, const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
BlitGL *blitter, BlitGL *blitter,
ClearMultiviewGL *multiviewClearer,
StateManagerGL *stateManager); StateManagerGL *stateManager);
~FramebufferGL() override; ~FramebufferGL() override;
...@@ -95,17 +98,6 @@ class FramebufferGL : public FramebufferImpl ...@@ -95,17 +98,6 @@ class FramebufferGL : public FramebufferImpl
void maskOutInactiveOutputDrawBuffers(gl::DrawBufferMask maxSet); void maskOutInactiveOutputDrawBuffers(gl::DrawBufferMask maxSet);
private: 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 syncClearState(const gl::Context *context, GLbitfield mask);
void syncClearBufferState(const gl::Context *context, GLenum buffer, GLint drawBuffer); void syncClearBufferState(const gl::Context *context, GLenum buffer, GLint drawBuffer);
...@@ -129,19 +121,11 @@ class FramebufferGL : public FramebufferImpl ...@@ -129,19 +121,11 @@ class FramebufferGL : public FramebufferImpl
GLubyte *pixels, GLubyte *pixels,
bool readLastRowSeparately) const; 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; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
const WorkaroundsGL &mWorkarounds; const WorkaroundsGL &mWorkarounds;
BlitGL *mBlitter; BlitGL *mBlitter;
ClearMultiviewGL *mMultiviewClearer;
GLuint mFramebufferID; GLuint mFramebufferID;
bool mIsDefault; bool mIsDefault;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/BlitGL.h" #include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/BufferGL.h" #include "libANGLE/renderer/gl/BufferGL.h"
#include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/CompilerGL.h" #include "libANGLE/renderer/gl/CompilerGL.h"
#include "libANGLE/renderer/gl/ContextGL.h" #include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FenceNVGL.h" #include "libANGLE/renderer/gl/FenceNVGL.h"
...@@ -168,6 +169,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at ...@@ -168,6 +169,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
mFunctions(functions), mFunctions(functions),
mStateManager(nullptr), mStateManager(nullptr),
mBlitter(nullptr), mBlitter(nullptr),
mMultiviewClearer(nullptr),
mUseDebugOutput(false), mUseDebugOutput(false),
mSkipDrawCalls(false), mSkipDrawCalls(false),
mCapsInitialized(false), mCapsInitialized(false),
...@@ -177,6 +179,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at ...@@ -177,6 +179,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds); nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds);
mStateManager = new StateManagerGL(mFunctions, getNativeCaps(), getNativeExtensions()); mStateManager = new StateManagerGL(mFunctions, getNativeCaps(), getNativeExtensions());
mBlitter = new BlitGL(functions, mWorkarounds, mStateManager); mBlitter = new BlitGL(functions, mWorkarounds, mStateManager);
mMultiviewClearer = new ClearMultiviewGL(functions, mStateManager);
bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) || bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) ||
mFunctions->hasGLExtension("GL_KHR_debug") || mFunctions->hasGLExtension("GL_KHR_debug") ||
...@@ -222,6 +225,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at ...@@ -222,6 +225,7 @@ RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &at
RendererGL::~RendererGL() RendererGL::~RendererGL()
{ {
SafeDelete(mBlitter); SafeDelete(mBlitter);
SafeDelete(mMultiviewClearer);
SafeDelete(mStateManager); SafeDelete(mStateManager);
} }
......
...@@ -36,6 +36,7 @@ struct BlockMemberInfo; ...@@ -36,6 +36,7 @@ struct BlockMemberInfo;
namespace rx namespace rx
{ {
class BlitGL; class BlitGL;
class ClearMultiviewGL;
class ContextImpl; class ContextImpl;
class FunctionsGL; class FunctionsGL;
class StateManagerGL; class StateManagerGL;
...@@ -159,6 +160,7 @@ class RendererGL : angle::NonCopyable ...@@ -159,6 +160,7 @@ class RendererGL : angle::NonCopyable
StateManagerGL *getStateManager() const { return mStateManager; } StateManagerGL *getStateManager() const { return mStateManager; }
const WorkaroundsGL &getWorkarounds() const { return mWorkarounds; } const WorkaroundsGL &getWorkarounds() const { return mWorkarounds; }
BlitGL *getBlitter() const { return mBlitter; } BlitGL *getBlitter() const { return mBlitter; }
ClearMultiviewGL *getMultiviewClearer() const { return mMultiviewClearer; }
MultiviewImplementationTypeGL getMultiviewImplementationType() const; MultiviewImplementationTypeGL getMultiviewImplementationType() const;
const gl::Caps &getNativeCaps() const; const gl::Caps &getNativeCaps() const;
...@@ -185,6 +187,7 @@ class RendererGL : angle::NonCopyable ...@@ -185,6 +187,7 @@ class RendererGL : angle::NonCopyable
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
BlitGL *mBlitter; BlitGL *mBlitter;
ClearMultiviewGL *mMultiviewClearer;
WorkaroundsGL mWorkarounds; WorkaroundsGL mWorkarounds;
......
...@@ -26,7 +26,8 @@ SurfaceGL::~SurfaceGL() ...@@ -26,7 +26,8 @@ SurfaceGL::~SurfaceGL()
FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data) FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{ {
return new FramebufferGL(data, mRenderer->getFunctions(), mRenderer->getStateManager(), 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) egl::Error SurfaceGL::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
......
...@@ -141,7 +141,8 @@ FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::Framebuff ...@@ -141,7 +141,8 @@ FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::Framebuff
{ {
// TODO(cwallez) assert it happens only once? // TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mRenderer->getWorkarounds(), return new FramebufferGL(mFramebuffer, state, mFunctions, mRenderer->getWorkarounds(),
mRenderer->getBlitter(), mStateManager); mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
} }
} // namespace rx } // namespace rx
...@@ -330,7 +330,7 @@ FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Framebuffe ...@@ -330,7 +330,7 @@ FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Framebuffe
{ {
// TODO(cwallez) assert it happens only once? // TODO(cwallez) assert it happens only once?
return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mRenderer->getBlitter(), return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mRenderer->getBlitter(),
mStateManager); mRenderer->getMultiviewClearer(), mStateManager);
} }
} // namespace rx } // namespace rx
...@@ -309,7 +309,8 @@ FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &s ...@@ -309,7 +309,8 @@ FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &s
{ {
return new FramebufferGL( return new FramebufferGL(
mGLFB, state, mDisplay->mFunctionsGL, mDisplay->getRenderer()->getWorkarounds(), 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() void DisplayOzone::Buffer::present()
......
...@@ -466,7 +466,8 @@ EGLint D3DTextureSurfaceWGL::getSwapBehavior() const ...@@ -466,7 +466,8 @@ EGLint D3DTextureSurfaceWGL::getSwapBehavior() const
FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::FramebufferState &data) FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::FramebufferState &data)
{ {
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds,
mRenderer->getBlitter(), mStateManager); mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
} }
HDC D3DTextureSurfaceWGL::getDC() const HDC D3DTextureSurfaceWGL::getDC() const
......
...@@ -270,7 +270,8 @@ FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer( ...@@ -270,7 +270,8 @@ FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
const gl::FramebufferState &data) const gl::FramebufferState &data)
{ {
return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds, return new FramebufferGL(mFramebufferID, data, mFunctionsGL, mWorkarounds,
mRenderer->getBlitter(), mStateManager); mRenderer->getBlitter(), mRenderer->getMultiviewClearer(),
mStateManager);
} }
HDC DXGISwapChainWindowSurfaceWGL::getDC() const HDC DXGISwapChainWindowSurfaceWGL::getDC() const
......
...@@ -559,6 +559,8 @@ ...@@ -559,6 +559,8 @@
'libANGLE/renderer/gl/BlitGL.h', 'libANGLE/renderer/gl/BlitGL.h',
'libANGLE/renderer/gl/BufferGL.cpp', 'libANGLE/renderer/gl/BufferGL.cpp',
'libANGLE/renderer/gl/BufferGL.h', 'libANGLE/renderer/gl/BufferGL.h',
'libANGLE/renderer/gl/ClearMultiviewGL.cpp',
'libANGLE/renderer/gl/ClearMultiviewGL.h',
'libANGLE/renderer/gl/CompilerGL.cpp', 'libANGLE/renderer/gl/CompilerGL.cpp',
'libANGLE/renderer/gl/CompilerGL.h', 'libANGLE/renderer/gl/CompilerGL.h',
'libANGLE/renderer/gl/ContextGL.cpp', 'libANGLE/renderer/gl/ContextGL.cpp',
......
...@@ -62,10 +62,10 @@ class FramebufferMultiviewTest : public ANGLETest ...@@ -62,10 +62,10 @@ class FramebufferMultiviewTest : public ANGLETest
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr; PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
}; };
class FramebufferMultiviewClearTest : public FramebufferMultiviewTest class FramebufferMultiviewSideBySideClearTest : public FramebufferMultiviewTest
{ {
protected: protected:
FramebufferMultiviewClearTest() {} FramebufferMultiviewSideBySideClearTest() {}
void initializeFBOs(size_t numColorBuffers, bool stencil, bool depth) void initializeFBOs(size_t numColorBuffers, bool stencil, bool depth)
{ {
...@@ -116,7 +116,7 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest ...@@ -116,7 +116,7 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
} }
glDrawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data()); 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); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
for (size_t i = 0u; i < numColorBuffers; ++i) for (size_t i = 0u; i < numColorBuffers; ++i)
{ {
...@@ -164,8 +164,118 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest ...@@ -164,8 +164,118 @@ class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
GLTexture mStencilTex; GLTexture mStencilTex;
}; };
// Test that the framebuffer tokens introduced by ANGLE_multiview can be used query the framebuffer class FramebufferMultiviewLayeredClearTest : public FramebufferMultiviewTest
// state and that their corresponding default values are correctly set. {
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) TEST_P(FramebufferMultiviewTest, DefaultState)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
...@@ -588,7 +698,7 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels) ...@@ -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 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()) if (!requestMultiviewExtension())
{ {
...@@ -707,7 +817,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered) ...@@ -707,7 +817,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE, EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
glCheckFramebufferStatus(GL_FRAMEBUFFER)); 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); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE, EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE,
...@@ -722,7 +832,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered) ...@@ -722,7 +832,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
} }
// Test that glClear clears all of the contents if the scissor test is disabled. // Test that glClear clears all of the contents if the scissor test is disabled.
TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest) TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
...@@ -756,7 +866,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest) ...@@ -756,7 +866,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest)
} }
// Test that glClear clears the depth buffer of each view. // Test that glClear clears the depth buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear) TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
...@@ -812,7 +922,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear) ...@@ -812,7 +922,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear)
} }
// Test that glClear clears the stencil buffer of each view. // Test that glClear clears the stencil buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear) TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
...@@ -876,7 +986,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear) ...@@ -876,7 +986,7 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear)
} }
// Test that glClearBufferf clears the color buffer of each view. // Test that glClearBufferf clears the color buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF) TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
...@@ -916,5 +1026,204 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF) ...@@ -916,5 +1026,204 @@ TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF)
checkAlternatingColumnsOfRedAndGreenInFBO(); 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(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