Commit 5c00d0db by Martin Radev Committed by Commit Bot

D3D11: Handle Clear* commands for side-by-side framebuffers

The patch modifies Clear11 to add support for clearing the color, depth and stencil attachments to a side-by-side framebuffer: - Color attachments are cleared through the command ClearView. - Depth and stencil attachments are cleared by drawing a quad on top of each view. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I5753a72222216a48cd954eb1219bc58f968735fc Reviewed-on: https://chromium-review.googlesource.com/603853 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent eef80e40
...@@ -453,6 +453,36 @@ bool FramebufferState::hasStencil() const ...@@ -453,6 +453,36 @@ bool FramebufferState::hasStencil() const
return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0); return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
} }
GLsizei FramebufferState::getNumViews() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
}
const std::vector<Offset> *FramebufferState::getViewportOffsets() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return nullptr;
}
return &attachment->getMultiviewViewportOffsets();
}
GLenum FramebufferState::getMultiviewLayout() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return GL_NONE;
}
return attachment->getMultiviewLayout();
}
Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id) Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
: mState(caps), : mState(caps),
mImpl(factory->createFramebuffer(mState)), mImpl(factory->createFramebuffer(mState)),
...@@ -1619,32 +1649,17 @@ int Framebuffer::getSamples(const ValidationContext *context) ...@@ -1619,32 +1649,17 @@ int Framebuffer::getSamples(const ValidationContext *context)
GLsizei Framebuffer::getNumViews() const GLsizei Framebuffer::getNumViews() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getNumViews();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
} }
const std::vector<Offset> *Framebuffer::getViewportOffsets() const const std::vector<Offset> *Framebuffer::getViewportOffsets() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getViewportOffsets();
if (attachment == nullptr)
{
return nullptr;
}
return &attachment->getMultiviewViewportOffsets();
} }
GLenum Framebuffer::getMultiviewLayout() const GLenum Framebuffer::getMultiviewLayout() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getMultiviewLayout();
if (attachment == nullptr)
{
return GL_NONE;
}
return attachment->getMultiviewLayout();
} }
} // namespace gl } // namespace gl
...@@ -92,6 +92,10 @@ class FramebufferState final : angle::NonCopyable ...@@ -92,6 +92,10 @@ class FramebufferState final : angle::NonCopyable
bool hasDepth() const; bool hasDepth() const;
bool hasStencil() const; bool hasStencil() const;
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
const std::vector<Offset> *getViewportOffsets() const;
private: private:
friend class Framebuffer; friend class Framebuffer;
......
...@@ -79,6 +79,19 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache, ...@@ -79,6 +79,19 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
return cacheDirty; return cacheDirty;
} }
bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
{
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
const auto &offset = viewportOffsets[i];
if (offset.x < 0 || offset.y < 0)
{
return false;
}
}
return true;
}
} // anonymous namespace } // anonymous namespace
Clear11::ShaderManager::ShaderManager() Clear11::ShaderManager::ShaderManager()
...@@ -364,26 +377,68 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -364,26 +377,68 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
framebufferSize = colorAttachment->getSize(); framebufferSize = colorAttachment->getSize();
} }
const bool isSideBySideFBO =
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
bool needScissoredClear = false; bool needScissoredClear = false;
std::vector<D3D11_RECT> scissorRects;
if (clearParams.scissorEnabled) if (clearParams.scissorEnabled)
{ {
const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
ASSERT(viewportOffsets != nullptr);
ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
if (clearParams.scissor.x >= framebufferSize.width || if (clearParams.scissor.x >= framebufferSize.width ||
clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
clearParams.scissor.x + clearParams.scissor.width <= 0 || clearParams.scissor.height == 0)
clearParams.scissor.y + clearParams.scissor.height <= 0 ||
clearParams.scissor.width == 0 || clearParams.scissor.height == 0)
{ {
// Scissor rect is outside the renderbuffer or is an empty rect // The check assumes that the viewport offsets are not negative as according to the
// ANGLE_multiview spec.
// Scissor rect is outside the renderbuffer or is an empty rect.
return gl::NoError(); return gl::NoError();
} }
if (isSideBySideFBO)
{
// We always have to do a scissor clear for side-by-side framebuffers.
needScissoredClear = true;
}
else
{
// Because the viewport offsets can generate scissor rectangles within the framebuffer's
// bounds, we can do this check only for non-side-by-side framebuffers.
if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
clearParams.scissor.y + clearParams.scissor.height <= 0)
{
// Scissor rect is outside the renderbuffer.
return gl::NoError();
}
needScissoredClear = needScissoredClear =
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height; clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
} }
if (needScissoredClear)
{
// Apply viewport offsets to compute the final scissor rectangles. This is valid also
// for non-side-by-side framebuffers, because the default viewport offset is {0,0}.
const size_t numViews = viewportOffsets->size();
scissorRects.reserve(numViews);
for (size_t i = 0u; i < numViews; ++i)
{
const gl::Offset &offset = (*viewportOffsets)[i];
D3D11_RECT rect;
int x = clearParams.scissor.x + offset.x;
int y = clearParams.scissor.y + offset.y;
rect.left = x;
rect.right = x + clearParams.scissor.width;
rect.top = y;
rect.bottom = y + clearParams.scissor.height;
scissorRects.emplace_back(rect);
}
}
}
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
...@@ -479,19 +534,17 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -479,19 +534,17 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
{ {
// We shouldn't reach here if deviceContext1 is unavailable. // We shouldn't reach here if deviceContext1 is unavailable.
ASSERT(deviceContext1); ASSERT(deviceContext1);
// There must be at least one scissor rectangle.
D3D11_RECT rect; ASSERT(!scissorRects.empty());
rect.left = clearParams.scissor.x; deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
rect.right = clearParams.scissor.x + clearParams.scissor.width; static_cast<UINT>(scissorRects.size()));
rect.top = clearParams.scissor.y;
rect.bottom = clearParams.scissor.y + clearParams.scissor.height;
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget) if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget)
{ {
if (clearParams.scissor.width <= 16 || clearParams.scissor.height <= 16) if (clearParams.scissor.width <= 16 || clearParams.scissor.height <= 16)
{ {
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1); deviceContext1->ClearView(framebufferRTV.get(), clearValues,
scissorRects.data(),
static_cast<UINT>(scissorRects.size()));
} }
} }
} }
...@@ -649,7 +702,7 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -649,7 +702,7 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
deviceContext->Unmap(mConstantBuffer.get(), 0); deviceContext->Unmap(mConstantBuffer.get(), 0);
} }
// Set the viewport to be the same size as the framebuffer // Set the viewport to be the same size as the framebuffer.
D3D11_VIEWPORT viewport; D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0; viewport.TopLeftX = 0;
viewport.TopLeftY = 0; viewport.TopLeftY = 0;
...@@ -667,9 +720,6 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -667,9 +720,6 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
if (needScissoredClear) if (needScissoredClear)
{ {
const D3D11_RECT scissorRect = {clearParams.scissor.x, clearParams.scissor.y,
clearParams.scissor.x1(), clearParams.scissor.y1()};
deviceContext->RSSetScissorRects(1, &scissorRect);
deviceContext->RSSetState(mScissorEnabledRasterizerState.get()); deviceContext->RSSetState(mScissorEnabledRasterizerState.get());
} }
else else
...@@ -710,8 +760,19 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -710,8 +760,19 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
// Apply render targets // Apply render targets
stateManager->setOneTimeRenderTargets(context, &rtvs[0], numRtvs, dsv); stateManager->setOneTimeRenderTargets(context, &rtvs[0], numRtvs, dsv);
// Draw the fullscreen quad // If scissors are necessary to be applied, then the number of clears is the number of scissor
// rects. If no scissors are necessary, then a single full-size clear is enough.
size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u;
for (size_t i = 0u; i < necessaryNumClears; ++i)
{
if (needScissoredClear)
{
ASSERT(i < scissorRects.size());
deviceContext->RSSetScissorRects(1, &scissorRects[i]);
}
// Draw the fullscreen quad.
deviceContext->Draw(6, 0); deviceContext->Draw(6, 0);
}
// Clean up // Clean up
mRenderer->markAllStateDirty(context); mRenderer->markAllStateDirty(context);
......
...@@ -12,6 +12,20 @@ ...@@ -12,6 +12,20 @@
using namespace angle; using namespace angle;
namespace
{
std::vector<GLenum> GetDrawBufferRange(size_t numColorAttachments)
{
std::vector<GLenum> drawBuffers(numColorAttachments);
const size_t kBase = static_cast<size_t>(GL_COLOR_ATTACHMENT0);
for (size_t i = 0u; i < drawBuffers.size(); ++i)
{
drawBuffers[i] = static_cast<GLenum>(kBase + i);
}
return drawBuffers;
}
} // namespace
class FramebufferMultiviewTest : public ANGLETest class FramebufferMultiviewTest : public ANGLETest
{ {
protected: protected:
...@@ -48,6 +62,108 @@ class FramebufferMultiviewTest : public ANGLETest ...@@ -48,6 +62,108 @@ class FramebufferMultiviewTest : public ANGLETest
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr; PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
}; };
class FramebufferMultiviewClearTest : public FramebufferMultiviewTest
{
protected:
FramebufferMultiviewClearTest() {}
void initializeFBOs(size_t numColorBuffers, bool stencil, bool depth)
{
const std::vector<GLenum> &drawBuffers = GetDrawBufferRange(2);
// Generate textures.
mColorTex.resize(numColorBuffers);
for (size_t i = 0u; i < numColorBuffers; ++i)
{
glBindTexture(GL_TEXTURE_2D, mColorTex[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
if (stencil)
{
glBindTexture(GL_TEXTURE_2D, mStencilTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 4, 2, 0, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8, nullptr);
}
else if (depth)
{
glBindTexture(GL_TEXTURE_2D, mDepthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 4, 2, 0, GL_DEPTH_COMPONENT,
GL_FLOAT, nullptr);
}
// Generate multiview fbo and attach textures.
const GLint kViewportOffsets[4] = {1, 0, 3, 0};
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
const size_t kBase = static_cast<size_t>(GL_COLOR_ATTACHMENT0);
for (size_t i = 0u; i < numColorBuffers; ++i)
{
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER,
static_cast<GLenum>(kBase + i),
mColorTex[i], 0, 2, &kViewportOffsets[0]);
}
if (stencil)
{
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT, mStencilTex,
0, 2, &kViewportOffsets[0]);
}
else if (depth)
{
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
mDepthTex, 0, 2, &kViewportOffsets[0]);
}
glDrawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data());
// Generate normal fbo and attach textures.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
for (size_t i = 0u; i < numColorBuffers; ++i)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, static_cast<GLenum>(kBase + i), GL_TEXTURE_2D,
mColorTex[i], 0);
}
if (stencil)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
mStencilTex, 0);
}
else if (depth)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDepthTex,
0);
}
glDrawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data());
ASSERT_GL_NO_ERROR();
}
void checkAlternatingColumnsOfRedAndGreenInFBO()
{
// column 0
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::red);
// column 1
EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
// column 2
EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(2, 1, GLColor::red);
// column 3
EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3, 1, GLColor::green);
}
GLFramebuffer mMultiviewFBO;
GLFramebuffer mNonMultiviewFBO;
std::vector<GLTexture> mColorTex;
GLTexture mDepthTex;
GLTexture mStencilTex;
};
// Test that the framebuffer tokens introduced by ANGLE_multiview can be used query the framebuffer // 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. // state and that their corresponding default values are correctly set.
TEST_P(FramebufferMultiviewTest, DefaultState) TEST_P(FramebufferMultiviewTest, DefaultState)
...@@ -472,59 +588,32 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels) ...@@ -472,59 +588,32 @@ 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(FramebufferMultiviewTest, SideBySideClear) TEST_P(FramebufferMultiviewClearTest, SideBySideColorBufferClear)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
return; return;
} }
GLFramebuffer multiviewFBO; initializeFBOs(1, false, false);
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
const GLint kViewportOffsets[4] = {1, 0, 3, 0};
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 2,
&kViewportOffsets[0]);
// Create and bind a normal framebuffer to access the 2D texture.
GLFramebuffer normalFBO;
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
// Clear the contents of the texture. // Clear the contents of the texture.
glClearColor(0, 0, 0, 1); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
// Bind and specify viewport/scissor dimensions for each view. // Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO); glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glViewport(0, 0, 1, 2); glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2); glScissor(0, 0, 1, 2);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glClearColor(1, 0, 0, 1); glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
// column 0
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::black);
// column 1
EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
// column 2
EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
EXPECT_PIXEL_COLOR_EQ(2, 1, GLColor::black);
// column 3 checkAlternatingColumnsOfRedAndGreenInFBO();
EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3, 1, GLColor::red);
} }
// Test that glFramebufferTextureMultiviewLayeredANGLE modifies the internal multiview state. // Test that glFramebufferTextureMultiviewLayeredANGLE modifies the internal multiview state.
...@@ -633,43 +722,187 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered) ...@@ -633,43 +722,187 @@ 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(FramebufferMultiviewTest, SideBySideClearWithDisabledScissorTest) TEST_P(FramebufferMultiviewClearTest, SideBySideClearWithDisabledScissorTest)
{ {
if (!requestMultiviewExtension()) if (!requestMultiviewExtension())
{ {
return; return;
} }
GLFramebuffer multiviewFBO; initializeFBOs(1, false, false);
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
GLTexture tex; // Clear the contents of the texture.
glBindTexture(GL_TEXTURE_2D, tex); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
const GLint kViewportOffsets[2] = {1, 0}; // Bind and specify viewport/scissor dimensions for each view.
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1, glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
&kViewportOffsets[0]); glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2);
// Create and bind a normal framebuffer to access the 2D texture. glClearColor(1, 0, 0, 1);
GLFramebuffer normalFBO; glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 2; ++j)
{
EXPECT_PIXEL_COLOR_EQ(i, j, GLColor::red);
}
}
}
// Test that glClear clears the depth buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideDepthBufferClear)
{
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, false, true);
glEnable(GL_DEPTH_TEST);
// Clear the contents of the texture. // Clear the contents of the texture.
glClearColor(0, 1, 0, 0); glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Bind and specify viewport/scissor dimensions for each view. // Dirty the depth and color buffers.
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO); glUniform3f(mColorUniformLoc, 1.0f, 0.0f, 0.0f);
drawQuad(program, "vPos", 0.0f, 1.0f, true);
// Switch to the multi-view framebuffer and clear only the rectangles covered by the views.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glViewport(0, 0, 1, 2); glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2); glScissor(0, 0, 1, 2);
glEnable(GL_SCISSOR_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
// Draw a fullscreen quad to fill the cleared regions.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glViewport(0, 0, 4, 2);
glScissor(0, 0, 4, 2);
glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
drawQuad(program, "vPos", 0.5f, 1.0f, true);
checkAlternatingColumnsOfRedAndGreenInFBO();
}
// Test that glClear clears the stencil buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideStencilBufferClear)
{
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, true, false);
glEnable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
// Set clear values and clear the whole framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glClearColor(0, 0, 0, 0);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Update stencil test to always replace the stencil value with 0xFF.
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 0xFF, 0);
// Draw a quad which covers the whole texture.
glUniform3f(mColorUniformLoc, 1.0f, 0.0f, 0.0f);
drawQuad(program, "vPos", 0.0f, 1.0f, true);
// Switch to multiview framebuffer and clear portions of the texture.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2);
glEnable(GL_SCISSOR_TEST);
glClear(GL_STENCIL_BUFFER_BIT);
// Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
// the test.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glViewport(0, 0, 4, 2);
glScissor(0, 0, 4, 2);
glStencilFunc(GL_EQUAL, 0x00, 0xFF);
glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
drawQuad(program, "vPos", 0.0f, 1.0f, true);
checkAlternatingColumnsOfRedAndGreenInFBO();
}
// Test that glClearBufferf clears the color buffer of each view.
TEST_P(FramebufferMultiviewClearTest, SideBySideClearBufferF)
{
if (!requestMultiviewExtension())
{
return;
}
initializeFBOs(2, false, false);
// Clear the contents of the texture.
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
glClearColor(1, 0, 0, 1); glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO); // Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2);
glEnable(GL_SCISSOR_TEST);
float kClearValues[4] = {0.f, 1.f, 0.f, 1.f};
glClearBufferfv(GL_COLOR, 1, kClearValues);
glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO);
// Check that glClearBufferfv has not modified the 0th color attachment.
glReadBuffer(GL_COLOR_ATTACHMENT0);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
for (int j = 0; j < 2; ++j) for (int j = 0; j < 2; ++j)
...@@ -677,6 +910,11 @@ TEST_P(FramebufferMultiviewTest, SideBySideClearWithDisabledScissorTest) ...@@ -677,6 +910,11 @@ TEST_P(FramebufferMultiviewTest, SideBySideClearWithDisabledScissorTest)
EXPECT_PIXEL_COLOR_EQ(i, j, GLColor::red); EXPECT_PIXEL_COLOR_EQ(i, j, GLColor::red);
} }
} }
// Check that glClearBufferfv has correctly modified the 1th color attachment.
glReadBuffer(GL_COLOR_ATTACHMENT1);
checkAlternatingColumnsOfRedAndGreenInFBO();
} }
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewClearTest, ES3_OPENGL(), ES3_D3D11());
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