Commit 3cd48fff by Geoff Lang Committed by Commit Bot

Implement robust resource initialization for OpenGL.

BUG=angleproject:2107 BUG=angleproject:2407 BUG=angleproject:2408 BUG=693090 Change-Id: I6444f80f9703d6341f2ec67518050adc88f71d96 Reviewed-on: https://chromium-review.googlesource.com/678482 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent daf120b4
......@@ -8,6 +8,7 @@
#include "libANGLE/renderer/gl/BlitGL.h"
#include "common/utilities.h"
#include "common/vector_utils.h"
#include "image_util/copyimage.h"
#include "libANGLE/Context.h"
......@@ -16,10 +17,12 @@
#include "libANGLE/renderer/Format.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RenderbufferGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
#include "libANGLE/renderer/renderer_utils.h"
using angle::Vector2;
......@@ -110,6 +113,76 @@ class ScopedGLState : angle::NonCopyable
const FunctionsGL *mFunctions;
};
gl::Error SetClearState(StateManagerGL *stateManager,
bool colorClear,
bool depthClear,
bool stencilClear,
GLbitfield *outClearMask)
{
*outClearMask = 0;
if (colorClear)
{
stateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 0.0f));
stateManager->setColorMask(true, true, true, true);
*outClearMask |= GL_COLOR_BUFFER_BIT;
}
if (depthClear)
{
stateManager->setDepthMask(true);
stateManager->setClearDepth(1.0f);
*outClearMask |= GL_DEPTH_BUFFER_BIT;
}
if (stencilClear)
{
stateManager->setClearStencil(0);
*outClearMask |= GL_STENCIL_BUFFER_BIT;
}
stateManager->setScissorTestEnabled(false);
return gl::NoError();
}
gl::Error PrepareForClear(StateManagerGL *stateManager,
GLenum sizedInternalFormat,
std::vector<GLenum> *outBindtargets,
GLbitfield *outClearMask)
{
const gl::InternalFormat &internalFormatInfo =
gl::GetSizedInternalFormatInfo(sizedInternalFormat);
bool bindDepth = internalFormatInfo.depthBits > 0;
bool bindStencil = internalFormatInfo.stencilBits > 0;
bool bindColor = !bindDepth && !bindStencil;
outBindtargets->clear();
if (bindColor)
{
outBindtargets->push_back(GL_COLOR_ATTACHMENT0);
}
if (bindDepth)
{
outBindtargets->push_back(GL_DEPTH_ATTACHMENT);
}
if (bindStencil)
{
outBindtargets->push_back(GL_STENCIL_ATTACHMENT);
}
ANGLE_TRY(SetClearState(stateManager, bindColor, bindDepth, bindStencil, outClearMask));
return gl::NoError();
}
void UnbindAttachments(const FunctionsGL *functions,
GLenum framebufferTarget,
const std::vector<GLenum> &bindTargets)
{
for (GLenum bindTarget : bindTargets)
{
functions->framebufferRenderbuffer(framebufferTarget, bindTarget, GL_RENDERBUFFER, 0);
}
}
} // anonymous namespace
BlitGL::BlitGL(const FunctionsGL *functions,
......@@ -636,6 +709,140 @@ gl::Error BlitGL::copyTexSubImage(TextureGL *source,
return gl::NoError();
}
gl::ErrorOrResult<bool> BlitGL::clearRenderableTexture(TextureGL *source,
GLenum sizedInternalFormat,
int numTextureLayers,
const gl::ImageIndex &imageIndex)
{
ANGLE_TRY(initializeResources());
std::vector<GLenum> bindTargets;
GLbitfield clearMask = 0;
ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &clearMask));
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
if (nativegl::UseTexImage2D(source->getType()))
{
ASSERT(numTextureLayers == 1);
for (GLenum bindTarget : bindTargets)
{
mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, bindTarget,
ToGLenum(imageIndex.target), source->getTextureID(),
imageIndex.mipIndex);
}
GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE)
{
mFunctions->clear(clearMask);
}
else
{
UnbindAttachments(mFunctions, GL_FRAMEBUFFER, bindTargets);
return false;
}
}
else
{
ASSERT(nativegl::UseTexImage3D(source->getType()));
// Check if it's possible to bind all layers of the texture at once
if (mFunctions->framebufferTexture && !imageIndex.hasLayer())
{
for (GLenum bindTarget : bindTargets)
{
mFunctions->framebufferTexture(GL_FRAMEBUFFER, bindTarget, source->getTextureID(),
imageIndex.mipIndex);
}
GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE)
{
mFunctions->clear(clearMask);
}
else
{
UnbindAttachments(mFunctions, GL_FRAMEBUFFER, bindTargets);
return false;
}
}
else
{
GLint firstLayer = 0;
GLint layerCount = numTextureLayers;
if (imageIndex.hasLayer())
{
firstLayer = imageIndex.layerIndex;
layerCount = imageIndex.numLayers;
}
for (GLint layer = 0; layer < layerCount; layer++)
{
for (GLenum bindTarget : bindTargets)
{
mFunctions->framebufferTextureLayer(GL_FRAMEBUFFER, bindTarget,
source->getTextureID(), imageIndex.mipIndex,
layer + firstLayer);
}
GLenum status = mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE)
{
mFunctions->clear(clearMask);
}
else
{
UnbindAttachments(mFunctions, GL_FRAMEBUFFER, bindTargets);
return false;
}
}
}
}
UnbindAttachments(mFunctions, GL_FRAMEBUFFER, bindTargets);
return true;
}
gl::Error BlitGL::clearRenderbuffer(RenderbufferGL *source, GLenum sizedInternalFormat)
{
ANGLE_TRY(initializeResources());
std::vector<GLenum> bindTargets;
GLbitfield clearMask = 0;
ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &clearMask));
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
for (GLenum bindTarget : bindTargets)
{
mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, bindTarget, GL_RENDERBUFFER,
source->getRenderbufferID());
}
mFunctions->clear(clearMask);
// Unbind
for (GLenum bindTarget : bindTargets)
{
mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, bindTarget, GL_RENDERBUFFER, 0);
}
return gl::NoError();
}
gl::Error BlitGL::clearFramebuffer(FramebufferGL *source)
{
// initializeResources skipped because no local state is used
// Clear all attachments
GLbitfield clearMask = 0;
ANGLE_TRY(SetClearState(mStateManager, true, true, true, &clearMask));
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, source->getFramebufferID());
mFunctions->clear(clearMask);
return gl::NoError();
}
gl::Error BlitGL::initializeResources()
{
for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
......
......@@ -19,6 +19,7 @@
namespace gl
{
class Framebuffer;
struct ImageIndex;
}
namespace rx
......@@ -26,6 +27,7 @@ namespace rx
class FramebufferGL;
class FunctionsGL;
class RenderbufferGL;
class StateManagerGL;
class TextureGL;
struct WorkaroundsGL;
......@@ -104,6 +106,15 @@ class BlitGL : angle::NonCopyable
const gl::Rectangle &sourceArea,
const gl::Offset &destOffset);
gl::ErrorOrResult<bool> clearRenderableTexture(TextureGL *source,
GLenum sizedInternalFormat,
int numTextureLayers,
const gl::ImageIndex &imageIndex);
gl::Error clearRenderbuffer(RenderbufferGL *source, GLenum sizedInternalFormat);
gl::Error clearFramebuffer(FramebufferGL *source);
gl::Error initializeResources();
private:
......
......@@ -78,7 +78,7 @@ TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
RenderbufferImpl *ContextGL::createRenderbuffer(const gl::RenderbufferState &state)
{
return new RenderbufferGL(state, getFunctions(), getWorkaroundsGL(), getStateManager(),
getNativeTextureCaps());
mRenderer->getBlitter(), getNativeTextureCaps());
}
BufferImpl *ContextGL::createBuffer(const gl::BufferState &state)
......
......@@ -11,6 +11,7 @@
#include "common/debug.h"
#include "libANGLE/Caps.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h"
......@@ -22,11 +23,13 @@ RenderbufferGL::RenderbufferGL(const gl::RenderbufferState &state,
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
StateManagerGL *stateManager,
BlitGL *blitter,
const gl::TextureCapsMap &textureCaps)
: RenderbufferImpl(state),
mFunctions(functions),
mWorkarounds(workarounds),
mStateManager(stateManager),
mBlitter(blitter),
mTextureCaps(textureCaps),
mRenderbufferID(0)
{
......@@ -52,6 +55,8 @@ gl::Error RenderbufferGL::setStorage(const gl::Context *context,
mFunctions->renderbufferStorage(GL_RENDERBUFFER, renderbufferFormat.internalFormat,
static_cast<GLsizei>(width), static_cast<GLsizei>(height));
mNativeInternalFormat = renderbufferFormat.internalFormat;
return gl::NoError();
}
......@@ -87,12 +92,16 @@ gl::Error RenderbufferGL::setStorageMultisample(const gl::Context *context,
} while (error != GL_NO_ERROR);
}
mNativeInternalFormat = renderbufferFormat.internalFormat;
return gl::NoError();
}
gl::Error RenderbufferGL::setStorageEGLImageTarget(const gl::Context *context, egl::Image *image)
{
UNIMPLEMENTED();
// TODO(geofflang): If implemented, be sure to update mNativeInternalFormat.
// http://anglebug.com/2412
UNREACHABLE();
return gl::InternalError();
}
......@@ -104,8 +113,7 @@ GLuint RenderbufferGL::getRenderbufferID() const
gl::Error RenderbufferGL::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex)
{
// TODO(jmadill):
return gl::NoError();
return mBlitter->clearRenderbuffer(this, mNativeInternalFormat);
}
} // namespace rx
......@@ -19,6 +19,7 @@ class TextureCapsMap;
namespace rx
{
class BlitGL;
class FunctionsGL;
class StateManagerGL;
struct WorkaroundsGL;
......@@ -30,6 +31,7 @@ class RenderbufferGL : public RenderbufferImpl
const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
StateManagerGL *stateManager,
BlitGL *blitter,
const gl::TextureCapsMap &textureCaps);
~RenderbufferGL() override;
......@@ -53,9 +55,12 @@ class RenderbufferGL : public RenderbufferImpl
const FunctionsGL *mFunctions;
const WorkaroundsGL &mWorkarounds;
StateManagerGL *mStateManager;
BlitGL *mBlitter;
const gl::TextureCapsMap &mTextureCaps;
GLuint mRenderbufferID;
GLenum mNativeInternalFormat;
};
}
......
......@@ -8,6 +8,8 @@
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
......@@ -44,7 +46,8 @@ egl::Error SurfaceGL::unMakeCurrent()
gl::Error SurfaceGL::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex)
{
// UNIMPLEMENTED();
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(mState.defaultFramebuffer);
ANGLE_TRY(mRenderer->getBlitter()->clearFramebuffer(framebufferGL));
return gl::NoError();
}
......
......@@ -203,7 +203,7 @@ EGLint WindowSurfaceGLX::isPostSubBufferSupported() const
EGLint WindowSurfaceGLX::getSwapBehavior() const
{
return EGL_BUFFER_PRESERVED;
return EGL_BUFFER_DESTROYED;
}
egl::Error WindowSurfaceGLX::checkForResize()
......
......@@ -1207,8 +1207,15 @@ bool SupportsNativeRendering(const FunctionsGL *functions,
{
// Some desktop drivers allow rendering to formats that are not required by the spec, this is
// exposed through the GL_FRAMEBUFFER_RENDERABLE query.
if (functions->isAtLeastGL(gl::Version(4, 3)) ||
functions->hasGLExtension("GL_ARB_internalformat_query2"))
bool hasInternalFormatQuery = functions->isAtLeastGL(gl::Version(4, 3)) ||
functions->hasGLExtension("GL_ARB_internalformat_query2");
// Some Intel drivers have a bug that returns GL_FULL_SUPPORT when asked if they support
// rendering to compressed texture formats yet return framebuffer incomplete when attempting to
// render to the format. Skip any native queries for compressed formats.
const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
if (hasInternalFormatQuery && !internalFormatInfo.compressed)
{
GLint framebufferRenderable = GL_NONE;
functions->getInternalformativ(ToGLenum(type), internalFormat, GL_FRAMEBUFFER_RENDERABLE, 1,
......@@ -1222,6 +1229,17 @@ bool SupportsNativeRendering(const FunctionsGL *functions,
return nativegl_gl::MeetsRequirements(functions, nativeInfo.framebufferAttachment);
}
}
bool UseTexImage2D(gl::TextureType textureType)
{
return textureType == gl::TextureType::_2D || textureType == gl::TextureType::CubeMap ||
textureType == gl::TextureType::Rectangle;
}
bool UseTexImage3D(gl::TextureType textureType)
{
return textureType == gl::TextureType::_2DArray || textureType == gl::TextureType::_3D;
}
}
bool CanMapBufferForRead(const FunctionsGL *functions)
......
......@@ -63,6 +63,8 @@ bool SupportsOcclusionQueries(const FunctionsGL *functions);
bool SupportsNativeRendering(const FunctionsGL *functions,
gl::TextureType type,
GLenum internalFormat);
bool UseTexImage2D(gl::TextureType textureType);
bool UseTexImage3D(gl::TextureType textureType);
}
bool CanMapBufferForRead(const FunctionsGL *functions);
......
......@@ -196,22 +196,11 @@ class RobustResourceInitTest : public ANGLETest
setRobustResourceInit(true);
}
bool isSkippedPlatform()
{
// Skip all tests on the OpenGL backend. It is not fully implemented but still needs to be
// exposed to test in Chromium.
return IsDesktopOpenGL() || IsOpenGLES();
}
bool hasGLExtension()
{
return !isSkippedPlatform() && extensionEnabled("GL_ANGLE_robust_resource_initialization");
}
bool hasGLExtension() { return extensionEnabled("GL_ANGLE_robust_resource_initialization"); }
bool hasEGLExtension()
{
return !isSkippedPlatform() &&
eglDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
return eglDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
"EGL_ANGLE_robust_resource_initialization");
}
......@@ -312,7 +301,7 @@ class RobustResourceInitTestES3 : public RobustResourceInitTest
// it only works on the implemented renderers
TEST_P(RobustResourceInitTest, ExpectedRendererSupport)
{
bool shouldHaveSupport = IsD3D11() || IsD3D11_FL93() || IsD3D9();
bool shouldHaveSupport = IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() || IsOpenGLES();
EXPECT_EQ(shouldHaveSupport, hasGLExtension());
EXPECT_EQ(shouldHaveSupport, hasEGLExtension());
EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit());
......@@ -512,7 +501,7 @@ void RobustResourceInitTest::checkCustomFramebufferNonZeroPixels(int fboWidth,
int index = (y * fboWidth + x);
if (x >= skipX && x < skipX + skipWidth && y >= skipY && y < skipY + skipHeight)
{
ASSERT_EQ(skip, data[index]);
ASSERT_EQ(skip, data[index]) << " at pixel " << x << ", " << y;
}
else
{
......@@ -563,6 +552,9 @@ TEST_P(RobustResourceInitTest, TexImageThenSubImage)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
// Put some data into the texture
GLTexture tex;
......@@ -650,6 +642,11 @@ TEST_P(RobustResourceInitTestES3, BindTexImage)
// Test skipped because EGL config cannot be used to create pbuffers.
ANGLE_SKIP_TEST_IF((surfaceType & EGL_PBUFFER_BIT) == 0);
EGLint bindToSurfaceRGBA = 0;
eglGetConfigAttrib(display, config, EGL_BIND_TO_TEXTURE_RGBA, &bindToSurfaceRGBA);
// Test skipped because EGL config cannot be used to create pbuffers.
ANGLE_SKIP_TEST_IF(bindToSurfaceRGBA == EGL_FALSE);
EGLint attribs[] = {
EGL_WIDTH, 32,
EGL_HEIGHT, 32,
......@@ -678,7 +675,14 @@ TEST_P(RobustResourceInitTestES3, BindTexImage)
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
EXPECT_PIXEL_COLOR_EQ(0, 0, clearColor);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
{
EXPECT_PIXEL_COLOR_EQ(0, 0, clearColor);
}
else
{
std::cout << "Read pixels check skipped because framebuffer was not complete." << std::endl;
}
eglDestroySurface(display, pbuffer);
}
......@@ -721,6 +725,9 @@ TEST_P(RobustResourceInitTest, ReadingPartiallyInitializedTexture)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
GLTexture tex;
setupTexture(&tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
......@@ -787,6 +794,9 @@ TEST_P(RobustResourceInitTestES3, MultisampledDepthInitializedCorrectly)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
const std::string vs = "attribute vec4 position; void main() { gl_Position = position; }";
const std::string fs = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
ANGLE_GL_PROGRAM(program, vs, fs);
......@@ -1023,6 +1033,9 @@ TEST_P(RobustResourceInitTestES3, BlitFramebufferOutOfBounds)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2408
ANGLE_SKIP_TEST_IF(IsOSX() && IsAMD());
// Initiate data to read framebuffer
constexpr int size = 8;
constexpr GLenum readbufferFormat = GL_RGBA8;
......@@ -1170,6 +1183,9 @@ TEST_P(RobustResourceInitTest, MaskedDepthClear)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
auto clearFunc = [](float depth) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepthf(depth);
......@@ -1184,6 +1200,9 @@ TEST_P(RobustResourceInitTestES3, MaskedDepthClearBuffer)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
auto clearFunc = [](float depth) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
......@@ -1243,6 +1262,9 @@ TEST_P(RobustResourceInitTest, MaskedStencilClear)
ANGLE_SKIP_TEST_IF(!hasGLExtension());
ANGLE_SKIP_TEST_IF(IsD3D11_FL93());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
auto clearFunc = [](GLint clearValue) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearStencil(clearValue);
......@@ -1257,6 +1279,9 @@ TEST_P(RobustResourceInitTestES3, MaskedStencilClearBuffer)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/2407
ANGLE_SKIP_TEST_IF(IsAndroid());
auto clearFunc = [](GLint clearValue) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
......
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