Commit 8acb1b61 by Olli Etuaho Committed by Commit Bot

Allow reads from a multiview framebuffer with one view

It's safe to read from a multiview framebuffer if it is layered and has just one view. The native OVR_multiview spec supports this as well. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I04e1364390574075f7e06e39a64e3bf05a539a05 Reviewed-on: https://chromium-review.googlesource.com/1156509 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2eb65034
...@@ -24,7 +24,7 @@ Status ...@@ -24,7 +24,7 @@ Status
Version Version
Last Modified Date: July 14, 2017 Last Modified Date: July 31, 2018
Author Revision: 1 Author Revision: 1
Number Number
...@@ -128,7 +128,9 @@ Additions to Chapter 3 of the OpenGL ES 3.0 Specification (Rasterization) ...@@ -128,7 +128,9 @@ Additions to Chapter 3 of the OpenGL ES 3.0 Specification (Rasterization)
"Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will
result in an INVALID_FRAMEBUFFER_OPERATION error if the multi-view result in an INVALID_FRAMEBUFFER_OPERATION error if the multi-view
layout of the current read framebuffer is not NONE." layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the
current read framebuffer is more than one."
Additions to Chapter 4 of the OpenGL ES 3.0 Specification Additions to Chapter 4 of the OpenGL ES 3.0 Specification
(Per-Fragment Operations and the Framebuffer) (Per-Fragment Operations and the Framebuffer)
...@@ -169,7 +171,9 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification ...@@ -169,7 +171,9 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification
Add to the end of the section: Add to the end of the section:
" ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if " ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
the multi-view layout of the current read framebuffer is not NONE." the multi-view layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the
current read framebuffer is more than one."
Modify section 4.3.3 (Copying pixels), p. 198 Modify section 4.3.3 (Copying pixels), p. 198
...@@ -181,8 +185,10 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification ...@@ -181,8 +185,10 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification
add a new paragraph: add a new paragraph:
"Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION "Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION
error if the multi-view layout of the current draw framebuffer or error if the multi-view layout of the current draw framebuffer is not NONE,
read framebuffer is not NONE." or the multi-view layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, or the number of views in the
current read framebuffer is more than one."
Modify section 4.4.2 (Attaching Images to Framebuffer Objects), p. 202 Modify section 4.4.2 (Attaching Images to Framebuffer Objects), p. 202
......
...@@ -2057,6 +2057,12 @@ GLenum Framebuffer::getMultiviewLayout() const ...@@ -2057,6 +2057,12 @@ GLenum Framebuffer::getMultiviewLayout() const
return mState.getMultiviewLayout(); return mState.getMultiviewLayout();
} }
bool Framebuffer::readDisallowedByMultiview() const
{
return (mState.getMultiviewLayout() != GL_NONE && mState.getNumViews() > 1) ||
mState.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
}
Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask) Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
{ {
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
......
...@@ -195,6 +195,7 @@ class Framebuffer final : public angle::ObserverInterface, public LabeledObject ...@@ -195,6 +195,7 @@ class Framebuffer final : public angle::ObserverInterface, public LabeledObject
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const; const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
GLenum getMultiviewLayout() const; GLenum getMultiviewLayout() const;
bool readDisallowedByMultiview() const;
GLsizei getNumViews() const; GLsizei getNumViews() const;
GLint getBaseViewIndex() const; GLint getBaseViewIndex() const;
const std::vector<Offset> *getViewportOffsets() const; const std::vector<Offset> *getViewportOffsets() const;
......
...@@ -1506,8 +1506,10 @@ bool ValidateBlitFramebufferParameters(Context *context, ...@@ -1506,8 +1506,10 @@ bool ValidateBlitFramebufferParameters(Context *context,
// ANGLE_multiview, Revision 1: // ANGLE_multiview, Revision 1:
// Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the
// multi-view layout of the current draw framebuffer or read framebuffer is not NONE. // multi-view layout of the current draw framebuffer is not NONE, or if the multi-view layout of
if (readFramebuffer->getMultiviewLayout() != GL_NONE) // the current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of
// views in the current read framebuffer is more than one.
if (readFramebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "Attempt to read from a multi-view framebuffer."); << "Attempt to read from a multi-view framebuffer.");
...@@ -2522,8 +2524,9 @@ bool ValidateCopyTexImageParametersBase(Context *context, ...@@ -2522,8 +2524,9 @@ bool ValidateCopyTexImageParametersBase(Context *context,
// ANGLE_multiview spec, Revision 1: // ANGLE_multiview spec, Revision 1:
// Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
// INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer
// is not NONE. // is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the current read
if (source->getMultiviewLayout() != GL_NONE) // framebuffer is more than one.
if (readFramebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "The active read framebuffer object has multiview attachments."); << "The active read framebuffer object has multiview attachments.");
...@@ -5707,8 +5710,9 @@ bool ValidateReadPixelsBase(Context *context, ...@@ -5707,8 +5710,9 @@ bool ValidateReadPixelsBase(Context *context,
// ANGLE_multiview, Revision 1: // ANGLE_multiview, Revision 1:
// ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the
// current read framebuffer is not NONE. // current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views
if (readBuffer->getMultiviewLayout() != GL_NONE) // in the current read framebuffer is more than one.
if (framebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "Attempting to read from a multi-view framebuffer."); << "Attempting to read from a multi-view framebuffer.");
......
...@@ -231,6 +231,7 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params) ...@@ -231,6 +231,7 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
mQuadVertexBuffer(0), mQuadVertexBuffer(0),
mQuadIndexBuffer(0), mQuadIndexBuffer(0),
m2DTexturedQuadProgram(0), m2DTexturedQuadProgram(0),
m3DTexturedQuadProgram(0),
mDeferContextInit(false) mDeferContextInit(false)
{ {
mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters); mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters);
...@@ -269,6 +270,10 @@ ANGLETestBase::~ANGLETestBase() ...@@ -269,6 +270,10 @@ ANGLETestBase::~ANGLETestBase()
{ {
glDeleteProgram(m2DTexturedQuadProgram); glDeleteProgram(m2DTexturedQuadProgram);
} }
if (m3DTexturedQuadProgram)
{
glDeleteProgram(m3DTexturedQuadProgram);
}
SafeDelete(mEGLWindow); SafeDelete(mEGLWindow);
} }
...@@ -639,13 +644,72 @@ GLuint ANGLETestBase::get2DTexturedQuadProgram() ...@@ -639,13 +644,72 @@ GLuint ANGLETestBase::get2DTexturedQuadProgram()
return m2DTexturedQuadProgram; return m2DTexturedQuadProgram;
} }
GLuint ANGLETestBase::get3DTexturedQuadProgram()
{
if (m3DTexturedQuadProgram)
{
return m3DTexturedQuadProgram;
}
const std::string &vs =
R"(#version 300 es
in vec2 position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(position, 0, 1);
texCoord = position * 0.5 + vec2(0.5);
})";
const std::string &fs =
R"(#version 300 es
precision highp float;
in vec2 texCoord;
out vec4 my_FragColor;
uniform highp sampler3D tex;
uniform float u_layer;
void main()
{
my_FragColor = texture(tex, vec3(texCoord, u_layer));
})";
m3DTexturedQuadProgram = CompileProgram(vs, fs);
return m3DTexturedQuadProgram;
}
void ANGLETestBase::draw2DTexturedQuad(GLfloat positionAttribZ, void ANGLETestBase::draw2DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale, GLfloat positionAttribXYScale,
bool useVertexBuffer) bool useVertexBuffer)
{ {
ASSERT_NE(0u, get2DTexturedQuadProgram()); ASSERT_NE(0u, get2DTexturedQuadProgram());
return drawQuad(get2DTexturedQuadProgram(), "position", positionAttribZ, positionAttribXYScale, drawQuad(get2DTexturedQuadProgram(), "position", positionAttribZ, positionAttribXYScale,
useVertexBuffer); useVertexBuffer);
}
void ANGLETestBase::draw3DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
float layer)
{
GLuint program = get3DTexturedQuadProgram();
ASSERT_NE(0u, program);
GLint activeProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(program);
}
glUniform1f(glGetUniformLocation(program, "u_layer"), layer);
drawQuad(program, "position", positionAttribZ, positionAttribXYScale, useVertexBuffer);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(static_cast<GLuint>(activeProgram));
}
} }
GLuint ANGLETestBase::compileShader(GLenum type, const std::string &source) GLuint ANGLETestBase::compileShader(GLenum type, const std::string &source)
......
...@@ -314,6 +314,12 @@ class ANGLETestBase ...@@ -314,6 +314,12 @@ class ANGLETestBase
GLfloat positionAttribXYScale, GLfloat positionAttribXYScale,
bool useVertexBuffer); bool useVertexBuffer);
// The layer parameter chooses the 3D texture layer to sample from.
void draw3DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
float layer);
static GLuint compileShader(GLenum type, const std::string &source); static GLuint compileShader(GLenum type, const std::string &source);
static bool extensionEnabled(const std::string &extName); static bool extensionEnabled(const std::string &extName);
static bool extensionRequestable(const std::string &extName); static bool extensionRequestable(const std::string &extName);
...@@ -362,6 +368,9 @@ class ANGLETestBase ...@@ -362,6 +368,9 @@ class ANGLETestBase
GLuint get2DTexturedQuadProgram(); GLuint get2DTexturedQuadProgram();
// Has a float uniform "u_layer" to choose the 3D texture layer.
GLuint get3DTexturedQuadProgram();
angle::PlatformMethods mPlatformMethods; angle::PlatformMethods mPlatformMethods;
class ScopedIgnorePlatformMessages : angle::NonCopyable class ScopedIgnorePlatformMessages : angle::NonCopyable
...@@ -399,6 +408,7 @@ class ANGLETestBase ...@@ -399,6 +408,7 @@ class ANGLETestBase
// Used for texture rendering. // Used for texture rendering.
GLuint m2DTexturedQuadProgram; GLuint m2DTexturedQuadProgram;
GLuint m3DTexturedQuadProgram;
TestPlatformContext mPlatformContext; TestPlatformContext mPlatformContext;
......
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