Commit 362876b1 by Jamie Madill Committed by Commit Bot

Cache Framebuffer completeness.

Improves performance on the render-to-texture microbenchmark by ~3x on the OpenGL back-end. Wipes out several of the top profling hotspots on that benchmark. BUG=angleproject:1388 Change-Id: I6a35a0b435b2ed3c83d32acdb9df090df98214ad Reviewed-on: https://chromium-review.googlesource.com/348957Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent 73d417ed
...@@ -24,22 +24,21 @@ ...@@ -24,22 +24,21 @@
#include "libANGLE/renderer/RenderbufferImpl.h" #include "libANGLE/renderer/RenderbufferImpl.h"
#include "libANGLE/renderer/SurfaceImpl.h" #include "libANGLE/renderer/SurfaceImpl.h"
using namespace angle;
namespace gl namespace gl
{ {
namespace namespace
{ {
void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId)
void BindResourceChannel(ChannelBinding *binding, FramebufferAttachmentObject *resource)
{ {
if (attachment->isAttached() && binding->bind(resource ? resource->getDirtyChannel() : nullptr);
attachment->type() == matchType &&
attachment->id() == matchId)
{
attachment->detach();
}
}
} }
} // anonymous namespace
FramebufferState::FramebufferState() FramebufferState::FramebufferState()
: mLabel(), : mLabel(),
mColorAttachments(1), mColorAttachments(1),
...@@ -171,16 +170,35 @@ bool FramebufferState::attachmentsHaveSameDimensions() const ...@@ -171,16 +170,35 @@ bool FramebufferState::attachmentsHaveSameDimensions() const
} }
Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id) Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
: mState(caps), mImpl(factory->createFramebuffer(mState)), mId(id) : mState(caps),
mImpl(factory->createFramebuffer(mState)),
mId(id),
mCachedStatus(),
mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
{ {
ASSERT(mId != 0); ASSERT(mId != 0);
ASSERT(mImpl != nullptr); ASSERT(mImpl != nullptr);
ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
{
mDirtyColorAttachmentBindings.push_back(ChannelBinding(
this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)));
}
} }
Framebuffer::Framebuffer(rx::SurfaceImpl *surface) Framebuffer::Framebuffer(rx::SurfaceImpl *surface)
: mState(), mImpl(surface->createDefaultFramebuffer(mState)), mId(0) : mState(),
mImpl(surface->createDefaultFramebuffer(mState)),
mId(0),
mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
{ {
ASSERT(mImpl != nullptr); ASSERT(mImpl != nullptr);
mDirtyColorAttachmentBindings.push_back(
ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
} }
Framebuffer::~Framebuffer() Framebuffer::~Framebuffer()
...@@ -210,13 +228,28 @@ void Framebuffer::detachRenderbuffer(GLuint renderbufferId) ...@@ -210,13 +228,28 @@ void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId)
{ {
for (auto &colorAttachment : mState.mColorAttachments) for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex)
{ {
DetachMatchingAttachment(&colorAttachment, resourceType, resourceId); detachMatchingAttachment(&mState.mColorAttachments[colorIndex], resourceType, resourceId,
DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
} }
DetachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId); detachMatchingAttachment(&mState.mDepthAttachment, resourceType, resourceId,
DetachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId); DIRTY_BIT_DEPTH_ATTACHMENT);
detachMatchingAttachment(&mState.mStencilAttachment, resourceType, resourceId,
DIRTY_BIT_STENCIL_ATTACHMENT);
}
void Framebuffer::detachMatchingAttachment(FramebufferAttachment *attachment,
GLenum matchType,
GLuint matchId,
size_t dirtyBit)
{
if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
{
attachment->detach();
mDirtyBits.set(dirtyBit);
}
} }
const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const
...@@ -397,6 +430,18 @@ GLenum Framebuffer::checkStatus(const ContextState &state) ...@@ -397,6 +430,18 @@ GLenum Framebuffer::checkStatus(const ContextState &state)
return GL_FRAMEBUFFER_COMPLETE; return GL_FRAMEBUFFER_COMPLETE;
} }
if (hasAnyDirtyBit() || !mCachedStatus.valid())
{
mCachedStatus = checkStatusImpl(state);
}
return mCachedStatus.value();
}
GLenum Framebuffer::checkStatusImpl(const ContextState &state)
{
ASSERT(mId != 0);
unsigned int colorbufferSize = 0; unsigned int colorbufferSize = 0;
int samples = -1; int samples = -1;
bool missingAttachment = true; bool missingAttachment = true;
...@@ -644,7 +689,7 @@ Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask) ...@@ -644,7 +689,7 @@ Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
{ {
if (context->getGLState().isRasterizerDiscardEnabled()) if (context->getGLState().isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
return mImpl->clear(context, mask); return mImpl->clear(context, mask);
...@@ -657,7 +702,7 @@ Error Framebuffer::clearBufferfv(rx::ContextImpl *context, ...@@ -657,7 +702,7 @@ Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
{ {
if (context->getGLState().isRasterizerDiscardEnabled()) if (context->getGLState().isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
return mImpl->clearBufferfv(context, buffer, drawbuffer, values); return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
...@@ -670,7 +715,7 @@ Error Framebuffer::clearBufferuiv(rx::ContextImpl *context, ...@@ -670,7 +715,7 @@ Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
{ {
if (context->getGLState().isRasterizerDiscardEnabled()) if (context->getGLState().isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
return mImpl->clearBufferuiv(context, buffer, drawbuffer, values); return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
...@@ -683,7 +728,7 @@ Error Framebuffer::clearBufferiv(rx::ContextImpl *context, ...@@ -683,7 +728,7 @@ Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
{ {
if (context->getGLState().isRasterizerDiscardEnabled()) if (context->getGLState().isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
return mImpl->clearBufferiv(context, buffer, drawbuffer, values); return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
...@@ -697,7 +742,7 @@ Error Framebuffer::clearBufferfi(rx::ContextImpl *context, ...@@ -697,7 +742,7 @@ Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
{ {
if (context->getGLState().isRasterizerDiscardEnabled()) if (context->getGLState().isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil); return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
...@@ -719,11 +764,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context, ...@@ -719,11 +764,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context,
GLenum type, GLenum type,
GLvoid *pixels) const GLvoid *pixels) const
{ {
Error error = mImpl->readPixels(context, area, format, type, pixels); ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
if (error.isError())
{
return error;
}
Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get(); Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
if (unpackBuffer) if (unpackBuffer)
...@@ -731,7 +772,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context, ...@@ -731,7 +772,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context,
unpackBuffer->onPixelUnpack(); unpackBuffer->onPixelUnpack();
} }
return Error(GL_NO_ERROR); return NoError();
} }
Error Framebuffer::blit(rx::ContextImpl *context, Error Framebuffer::blit(rx::ContextImpl *context,
...@@ -745,16 +786,15 @@ Error Framebuffer::blit(rx::ContextImpl *context, ...@@ -745,16 +786,15 @@ Error Framebuffer::blit(rx::ContextImpl *context,
int Framebuffer::getSamples(const ContextState &state) int Framebuffer::getSamples(const ContextState &state)
{ {
if (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE) if (complete(state))
{ {
// for a complete framebuffer, all attachments must have the same sample count // For a complete framebuffer, all attachments must have the same sample count.
// in this case return the first nonzero sample size // In this case return the first nonzero sample size.
for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments) const auto *firstColorAttachment = mState.getFirstColorAttachment();
if (firstColorAttachment)
{ {
if (colorAttachment.isAttached()) ASSERT(firstColorAttachment->isAttached());
{ return firstColorAttachment->getSamples();
return colorAttachment.getSamples();
}
} }
} }
...@@ -791,6 +831,8 @@ void Framebuffer::setAttachment(GLenum type, ...@@ -791,6 +831,8 @@ void Framebuffer::setAttachment(GLenum type,
mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj); mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT); mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT); mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
} }
else else
{ {
...@@ -800,22 +842,26 @@ void Framebuffer::setAttachment(GLenum type, ...@@ -800,22 +842,26 @@ void Framebuffer::setAttachment(GLenum type,
case GL_DEPTH_ATTACHMENT: case GL_DEPTH_ATTACHMENT:
mState.mDepthAttachment.attach(type, binding, textureIndex, resource); mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT); mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
break; BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
break;
case GL_STENCIL: case GL_STENCIL:
case GL_STENCIL_ATTACHMENT: case GL_STENCIL_ATTACHMENT:
mState.mStencilAttachment.attach(type, binding, textureIndex, resource); mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT); mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
break; BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
break;
case GL_BACK: case GL_BACK:
mState.mColorAttachments[0].attach(type, binding, textureIndex, resource); mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0); mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
break; // No need for a resource binding for the default FBO, it's always complete.
break;
default: default:
{ {
size_t colorIndex = binding - GL_COLOR_ATTACHMENT0; size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
ASSERT(colorIndex < mState.mColorAttachments.size()); ASSERT(colorIndex < mState.mColorAttachments.size());
mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource); mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex); mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
} }
break; break;
} }
...@@ -827,27 +873,25 @@ void Framebuffer::resetAttachment(GLenum binding) ...@@ -827,27 +873,25 @@ void Framebuffer::resetAttachment(GLenum binding)
setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr); setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
} }
void Framebuffer::syncState() const void Framebuffer::syncState()
{ {
if (mDirtyBits.any()) if (mDirtyBits.any())
{ {
mImpl->syncState(mDirtyBits); mImpl->syncState(mDirtyBits);
mDirtyBits.reset(); mDirtyBits.reset();
mCachedStatus.reset();
} }
} }
int Framebuffer::getCachedSamples(const ContextState &state) const void Framebuffer::signal(SignalToken token)
{ {
// TODO(jmadill): Framebuffer samples caching. // TOOD(jmadill): Make this only update individual attachments to do less work.
ASSERT(mDirtyBits.none()); mCachedStatus.reset();
return const_cast<Framebuffer *>(this)->getSamples(state);
} }
GLenum Framebuffer::getCachedStatus(const ContextState &state) const bool Framebuffer::complete(const ContextState &state)
{ {
// TODO(jmadill): Framebuffer status caching. return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
ASSERT(mDirtyBits.none());
return const_cast<Framebuffer *>(this)->checkStatus(state);
} }
} // namespace gl } // namespace gl
...@@ -12,12 +12,14 @@ ...@@ -12,12 +12,14 @@
#include <vector> #include <vector>
#include "common/Optional.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/Constants.h" #include "libANGLE/Constants.h"
#include "libANGLE/Debug.h" #include "libANGLE/Debug.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/RefCountObject.h" #include "libANGLE/RefCountObject.h"
#include "libANGLE/signal_utils.h"
namespace rx namespace rx
{ {
...@@ -86,7 +88,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -86,7 +88,7 @@ class FramebufferState final : angle::NonCopyable
GLenum mReadBufferState; GLenum mReadBufferState;
}; };
class Framebuffer final : public LabeledObject class Framebuffer final : public LabeledObject, public angle::SignalReceiver
{ {
public: public:
Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id); Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id);
...@@ -140,10 +142,8 @@ class Framebuffer final : public LabeledObject ...@@ -140,10 +142,8 @@ class Framebuffer final : public LabeledObject
int getSamples(const ContextState &state); int getSamples(const ContextState &state);
GLenum checkStatus(const ContextState &state); GLenum checkStatus(const ContextState &state);
// These methods do not change any state. // Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE.
// TODO(jmadill): Remove ContextState parameter when able. bool complete(const ContextState &state);
int getCachedSamples(const ContextState &state) const;
GLenum getCachedStatus(const ContextState &state) const;
bool hasValidDepthStencil() const; bool hasValidDepthStencil() const;
...@@ -200,19 +200,31 @@ class Framebuffer final : public LabeledObject ...@@ -200,19 +200,31 @@ class Framebuffer final : public LabeledObject
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits; typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
bool hasAnyDirtyBit() const { return mDirtyBits.any(); } bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
void syncState() const; void syncState();
protected: // angle::SignalReceiver implementation
void signal(angle::SignalToken token) override;
private:
void detachResourceById(GLenum resourceType, GLuint resourceId); void detachResourceById(GLenum resourceType, GLuint resourceId);
void detachMatchingAttachment(FramebufferAttachment *attachment,
GLenum matchType,
GLuint matchId,
size_t dirtyBit);
GLenum checkStatusImpl(const ContextState &state);
FramebufferState mState; FramebufferState mState;
rx::FramebufferImpl *mImpl; rx::FramebufferImpl *mImpl;
GLuint mId; GLuint mId;
// TODO(jmadill): See if we can make this non-mutable. Optional<GLenum> mCachedStatus;
mutable DirtyBits mDirtyBits; std::vector<angle::ChannelBinding> mDirtyColorAttachmentBindings;
angle::ChannelBinding mDirtyDepthAttachmentBinding;
angle::ChannelBinding mDirtyStencilAttachmentBinding;
DirtyBits mDirtyBits;
}; };
} } // namespace gl
#endif // LIBANGLE_FRAMEBUFFER_H_ #endif // LIBANGLE_FRAMEBUFFER_H_
...@@ -233,4 +233,9 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget( ...@@ -233,4 +233,9 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget(
return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut); return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut);
} }
angle::BroadcastChannel *FramebufferAttachmentObject::getDirtyChannel()
{
return &mDirtyChannel;
}
} // namespace gl } // namespace gl
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/ImageIndex.h" #include "libANGLE/ImageIndex.h"
#include "libANGLE/signal_utils.h"
namespace egl namespace egl
{ {
...@@ -165,8 +166,12 @@ class FramebufferAttachmentObject ...@@ -165,8 +166,12 @@ class FramebufferAttachmentObject
Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target, Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target,
rx::FramebufferAttachmentRenderTarget **rtOut) const; rx::FramebufferAttachmentRenderTarget **rtOut) const;
angle::BroadcastChannel *getDirtyChannel();
protected: protected:
virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0; virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
angle::BroadcastChannel mDirtyChannel;
}; };
inline Extents FramebufferAttachment::getSize() const inline Extents FramebufferAttachment::getSize() const
......
...@@ -49,47 +49,39 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh ...@@ -49,47 +49,39 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh
{ {
orphanImages(); orphanImages();
Error error = mRenderbuffer->setStorage(internalformat, width, height); ANGLE_TRY(mRenderbuffer->setStorage(internalformat, width, height));
if (error.isError())
{
return error;
}
mWidth = static_cast<GLsizei>(width); mWidth = static_cast<GLsizei>(width);
mHeight = static_cast<GLsizei>(height); mHeight = static_cast<GLsizei>(height);
mInternalFormat = internalformat; mInternalFormat = internalformat;
mSamples = 0; mSamples = 0;
return Error(GL_NO_ERROR); mDirtyChannel.signal();
return NoError();
} }
Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height)
{ {
orphanImages(); orphanImages();
Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); ANGLE_TRY(mRenderbuffer->setStorageMultisample(samples, internalformat, width, height));
if (error.isError())
{
return error;
}
mWidth = static_cast<GLsizei>(width); mWidth = static_cast<GLsizei>(width);
mHeight = static_cast<GLsizei>(height); mHeight = static_cast<GLsizei>(height);
mInternalFormat = internalformat; mInternalFormat = internalformat;
mSamples = static_cast<GLsizei>(samples); mSamples = static_cast<GLsizei>(samples);
return Error(GL_NO_ERROR); mDirtyChannel.signal();
return NoError();
} }
Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image) Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
{ {
orphanImages(); orphanImages();
Error error = mRenderbuffer->setStorageEGLImageTarget(image); ANGLE_TRY(mRenderbuffer->setStorageEGLImageTarget(image));
if (error.isError())
{
return error;
}
setTargetImage(image); setTargetImage(image);
...@@ -98,7 +90,9 @@ Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image) ...@@ -98,7 +90,9 @@ Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
mInternalFormat = image->getInternalFormat(); mInternalFormat = image->getInternalFormat();
mSamples = 0; mSamples = 0;
return Error(GL_NO_ERROR); mDirtyChannel.signal();
return NoError();
} }
rx::RenderbufferImpl *Renderbuffer::getImplementation() rx::RenderbufferImpl *Renderbuffer::getImplementation()
...@@ -181,4 +175,4 @@ Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /* ...@@ -181,4 +175,4 @@ Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /*
{ {
return Extents(mWidth, mHeight, 1); return Extents(mWidth, mHeight, 1);
} }
} } // namespace gl
...@@ -779,17 +779,14 @@ Error Texture::setImage(const PixelUnpackState &unpackState, ...@@ -779,17 +779,14 @@ Error Texture::setImage(const PixelUnpackState &unpackState,
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages(); orphanImages();
Error error = ANGLE_TRY(
mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels); mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels));
if (error.isError())
{
return error;
}
mState.setImageDesc(target, level, mState.setImageDesc(target, level,
ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
mDirtyChannel.signal();
return Error(GL_NO_ERROR); return NoError();
} }
Error Texture::setSubImage(const PixelUnpackState &unpackState, Error Texture::setSubImage(const PixelUnpackState &unpackState,
...@@ -820,17 +817,14 @@ Error Texture::setCompressedImage(const PixelUnpackState &unpackState, ...@@ -820,17 +817,14 @@ Error Texture::setCompressedImage(const PixelUnpackState &unpackState,
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages(); orphanImages();
Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpackState, ANGLE_TRY(mTexture->setCompressedImage(target, level, internalFormat, size, unpackState,
imageSize, pixels); imageSize, pixels));
if (error.isError())
{
return error;
}
mState.setImageDesc(target, level, mState.setImageDesc(target, level,
ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
mDirtyChannel.signal();
return Error(GL_NO_ERROR); return NoError();
} }
Error Texture::setCompressedSubImage(const PixelUnpackState &unpackState, Error Texture::setCompressedSubImage(const PixelUnpackState &unpackState,
...@@ -858,17 +852,14 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre ...@@ -858,17 +852,14 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages(); orphanImages();
Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); ANGLE_TRY(mTexture->copyImage(target, level, sourceArea, internalFormat, source));
if (error.isError())
{
return error;
}
mState.setImageDesc(target, level, mState.setImageDesc(target, level,
ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
mDirtyChannel.signal();
return Error(GL_NO_ERROR); return NoError();
} }
Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea,
...@@ -888,17 +879,15 @@ Error Texture::setStorage(GLenum target, GLsizei levels, GLenum internalFormat, ...@@ -888,17 +879,15 @@ Error Texture::setStorage(GLenum target, GLsizei levels, GLenum internalFormat,
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages(); orphanImages();
Error error = mTexture->setStorage(target, levels, internalFormat, size); ANGLE_TRY(mTexture->setStorage(target, levels, internalFormat, size));
if (error.isError())
{
return error;
}
mState.mImmutableFormat = true; mState.mImmutableFormat = true;
mState.mImmutableLevels = static_cast<GLuint>(levels); mState.mImmutableLevels = static_cast<GLuint>(levels);
mState.clearImageDescs(); mState.clearImageDescs();
mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, internalFormat); mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, internalFormat);
return Error(GL_NO_ERROR); mDirtyChannel.signal();
return NoError();
} }
Error Texture::generateMipmap() Error Texture::generateMipmap()
...@@ -926,6 +915,8 @@ Error Texture::generateMipmap() ...@@ -926,6 +915,8 @@ Error Texture::generateMipmap()
baseImageInfo.internalFormat); baseImageInfo.internalFormat);
} }
mDirtyChannel.signal();
return NoError(); return NoError();
} }
...@@ -946,6 +937,7 @@ void Texture::bindTexImageFromSurface(egl::Surface *surface) ...@@ -946,6 +937,7 @@ void Texture::bindTexImageFromSurface(egl::Surface *surface)
Extents size(surface->getWidth(), surface->getHeight(), 1); Extents size(surface->getWidth(), surface->getHeight(), 1);
ImageDesc desc(size, surface->getConfig()->renderTargetFormat); ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
mState.setImageDesc(mState.mTarget, 0, desc); mState.setImageDesc(mState.mTarget, 0, desc);
mDirtyChannel.signal();
} }
void Texture::releaseTexImageFromSurface() void Texture::releaseTexImageFromSurface()
...@@ -957,6 +949,7 @@ void Texture::releaseTexImageFromSurface() ...@@ -957,6 +949,7 @@ void Texture::releaseTexImageFromSurface()
// Erase the image info for level 0 // Erase the image info for level 0
ASSERT(mState.mTarget == GL_TEXTURE_2D); ASSERT(mState.mTarget == GL_TEXTURE_2D);
mState.clearImageDesc(mState.mTarget, 0); mState.clearImageDesc(mState.mTarget, 0);
mDirtyChannel.signal();
} }
void Texture::bindStream(egl::Stream *stream) void Texture::bindStream(egl::Stream *stream)
...@@ -984,6 +977,7 @@ void Texture::acquireImageFromStream(const egl::Stream::GLTextureDescription &de ...@@ -984,6 +977,7 @@ void Texture::acquireImageFromStream(const egl::Stream::GLTextureDescription &de
Extents size(desc.width, desc.height, 1); Extents size(desc.width, desc.height, 1);
mState.setImageDesc(mState.mTarget, 0, ImageDesc(size, desc.internalFormat)); mState.setImageDesc(mState.mTarget, 0, ImageDesc(size, desc.internalFormat));
mDirtyChannel.signal();
} }
void Texture::releaseImageFromStream() void Texture::releaseImageFromStream()
...@@ -993,6 +987,7 @@ void Texture::releaseImageFromStream() ...@@ -993,6 +987,7 @@ void Texture::releaseImageFromStream()
// Set to incomplete // Set to incomplete
mState.clearImageDesc(mState.mTarget, 0); mState.clearImageDesc(mState.mTarget, 0);
mDirtyChannel.signal();
} }
void Texture::releaseTexImageInternal() void Texture::releaseTexImageInternal()
...@@ -1016,11 +1011,7 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget) ...@@ -1016,11 +1011,7 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages(); orphanImages();
Error error = mTexture->setEGLImageTarget(target, imageTarget); ANGLE_TRY(mTexture->setEGLImageTarget(target, imageTarget));
if (error.isError())
{
return error;
}
setTargetImage(imageTarget); setTargetImage(imageTarget);
...@@ -1031,8 +1022,9 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget) ...@@ -1031,8 +1022,9 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
mState.clearImageDescs(); mState.clearImageDescs();
mState.setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); mState.setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
mDirtyChannel.signal();
return Error(GL_NO_ERROR); return NoError();
} }
Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const
...@@ -1070,4 +1062,4 @@ rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const ...@@ -1070,4 +1062,4 @@ rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
{ {
return mTexture; return mTexture;
} }
} } // namespace gl
...@@ -56,19 +56,14 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal ...@@ -56,19 +56,14 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal
} }
RenderTargetD3D *newRT = NULL; RenderTargetD3D *newRT = NULL;
gl::Error error = ANGLE_TRY(mRenderer->createRenderTarget(static_cast<int>(width), static_cast<int>(height),
mRenderer->createRenderTarget(static_cast<int>(width), static_cast<int>(height), creationFormat, static_cast<GLsizei>(samples), &newRT));
creationFormat, static_cast<GLsizei>(samples), &newRT);
if (error.isError())
{
return error;
}
SafeDelete(mRenderTarget); SafeDelete(mRenderTarget);
mImage = nullptr; mImage = nullptr;
mRenderTarget = newRT; mRenderTarget = newRT;
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image) gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
...@@ -76,7 +71,7 @@ gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image) ...@@ -76,7 +71,7 @@ gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
mImage = GetImplAs<EGLImageD3D>(image); mImage = GetImplAs<EGLImageD3D>(image);
SafeDelete(mRenderTarget); SafeDelete(mRenderTarget);
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget) gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget)
...@@ -88,7 +83,7 @@ gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget) ...@@ -88,7 +83,7 @@ gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget)
else else
{ {
*outRenderTarget = mRenderTarget; *outRenderTarget = mRenderTarget;
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
} }
......
...@@ -38,11 +38,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme ...@@ -38,11 +38,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme
TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture); TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
TextureStorage *texStorage = nullptr; TextureStorage *texStorage = nullptr;
gl::Error error = textureD3D->getNativeTexture(&texStorage); ANGLE_TRY(textureD3D->getNativeTexture(&texStorage));
if (error.isError())
{
return error;
}
if (texStorage) if (texStorage)
{ {
...@@ -53,7 +49,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme ...@@ -53,7 +49,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme
} }
} }
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
void UpdateCachedRenderTarget(const gl::FramebufferAttachment *attachment, void UpdateCachedRenderTarget(const gl::FramebufferAttachment *attachment,
...@@ -99,33 +95,19 @@ gl::Error Framebuffer11::invalidateSwizzles() const ...@@ -99,33 +95,19 @@ gl::Error Framebuffer11::invalidateSwizzles() const
{ {
if (colorAttachment.isAttached()) if (colorAttachment.isAttached())
{ {
gl::Error error = InvalidateAttachmentSwizzles(&colorAttachment); ANGLE_TRY(InvalidateAttachmentSwizzles(&colorAttachment));
if (error.isError())
{
return error;
}
} }
} }
gl::Error error = InvalidateAttachmentSwizzles(mState.getDepthAttachment()); ANGLE_TRY(InvalidateAttachmentSwizzles(mState.getDepthAttachment()));
if (error.isError()) ANGLE_TRY(InvalidateAttachmentSwizzles(mState.getStencilAttachment()));
{
return error;
}
error = InvalidateAttachmentSwizzles(mState.getStencilAttachment());
if (error.isError())
{
return error;
}
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error Framebuffer11::clearImpl(ContextImpl *context, const ClearParameters &clearParams) gl::Error Framebuffer11::clearImpl(ContextImpl *context, const ClearParameters &clearParams)
{ {
Clear11 *clearer = mRenderer->getClearer(); Clear11 *clearer = mRenderer->getClearer();
gl::Error error(GL_NO_ERROR);
const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment(); const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment();
if (clearParams.scissorEnabled == true && colorAttachment != nullptr && if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
...@@ -139,25 +121,16 @@ gl::Error Framebuffer11::clearImpl(ContextImpl *context, const ClearParameters & ...@@ -139,25 +121,16 @@ gl::Error Framebuffer11::clearImpl(ContextImpl *context, const ClearParameters &
presentPathFastClearParams.scissor.y = framebufferSize.height - presentPathFastClearParams.scissor.y = framebufferSize.height -
presentPathFastClearParams.scissor.y - presentPathFastClearParams.scissor.y -
presentPathFastClearParams.scissor.height; presentPathFastClearParams.scissor.height;
error = clearer->clearFramebuffer(presentPathFastClearParams, mState); ANGLE_TRY(clearer->clearFramebuffer(presentPathFastClearParams, mState));
} }
else else
{ {
error = clearer->clearFramebuffer(clearParams, mState); ANGLE_TRY(clearer->clearFramebuffer(clearParams, mState));
}
if (error.isError())
{
return error;
} }
error = invalidateSwizzles(); ANGLE_TRY(invalidateSwizzles());
if (error.isError())
{
return error;
}
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error Framebuffer11::invalidate(size_t count, const GLenum *attachments) gl::Error Framebuffer11::invalidate(size_t count, const GLenum *attachments)
...@@ -177,7 +150,7 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, ...@@ -177,7 +150,7 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments,
if (!deviceContext1) if (!deviceContext1)
{ {
// DiscardView() is only supported on ID3D11DeviceContext1 // DiscardView() is only supported on ID3D11DeviceContext1
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
bool foundDepth = false; bool foundDepth = false;
...@@ -206,37 +179,10 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, ...@@ -206,37 +179,10 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments,
ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) || ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) ||
(attachments[i] == GL_COLOR)); (attachments[i] == GL_COLOR));
RenderTarget11 *renderTarget = nullptr; size_t colorIndex =
ID3D11View *colorView = nullptr; (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0));
gl::Error error(GL_NO_ERROR); auto colorAttachment = mState.getColorAttachment(colorIndex);
size_t colorAttachmentID = 0; ANGLE_TRY(invalidateAttachment(colorAttachment));
if (attachments[i] == GL_COLOR)
{
colorAttachmentID = 0;
}
else
{
colorAttachmentID = attachments[i] - GL_COLOR_ATTACHMENT0;
}
if (mState.getColorAttachment(static_cast<unsigned int>(colorAttachmentID)))
{
error = mState.getColorAttachment(static_cast<unsigned int>(colorAttachmentID))
->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
colorView = renderTarget->getRenderTargetView();
if (colorView != nullptr)
{
deviceContext1->DiscardView(colorView);
}
}
break; break;
} }
} }
...@@ -268,51 +214,39 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, ...@@ -268,51 +214,39 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments,
if (discardDepth && mState.getDepthAttachment()) if (discardDepth && mState.getDepthAttachment())
{ {
RenderTarget11 *renderTarget = nullptr; ANGLE_TRY(invalidateAttachment(mState.getDepthAttachment()));
ID3D11View *depthView = nullptr;
gl::Error error(GL_NO_ERROR);
error = mState.getDepthAttachment()->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
depthView = renderTarget->getDepthStencilView();
if (depthView != nullptr)
{
deviceContext1->DiscardView(depthView);
}
} }
if (discardStencil && mState.getStencilAttachment()) if (discardStencil && mState.getStencilAttachment())
{ {
RenderTarget11 *renderTarget = nullptr; ANGLE_TRY(invalidateAttachment(mState.getStencilAttachment()));
ID3D11View *stencilView = nullptr;
gl::Error error(GL_NO_ERROR);
error = mState.getStencilAttachment()->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
stencilView = renderTarget->getDepthStencilView();
if (stencilView != nullptr)
{
deviceContext1->DiscardView(stencilView);
}
} }
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
{ {
// A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED() // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED()
return gl::Error(GL_NO_ERROR); return gl::NoError();
}
gl::Error Framebuffer11::invalidateAttachment(const gl::FramebufferAttachment *attachment) const
{
ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
ASSERT(deviceContext1);
ASSERT(attachment && attachment->isAttached());
RenderTarget11 *renderTarget = nullptr;
ANGLE_TRY(attachment->getRenderTarget(&renderTarget));
ID3D11View *view = renderTarget->getRenderTargetView();
if (view != nullptr)
{
deviceContext1->DiscardView(view);
}
return gl::NoError();
} }
gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area, gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area,
...@@ -361,11 +295,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea, ...@@ -361,11 +295,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
ASSERT(readBuffer); ASSERT(readBuffer);
RenderTargetD3D *readRenderTarget = nullptr; RenderTargetD3D *readRenderTarget = nullptr;
gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); ANGLE_TRY(readBuffer->getRenderTarget(&readRenderTarget));
if (error.isError())
{
return error;
}
ASSERT(readRenderTarget); ASSERT(readRenderTarget);
const auto &colorAttachments = mState.getColorAttachments(); const auto &colorAttachments = mState.getColorAttachments();
...@@ -379,11 +309,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea, ...@@ -379,11 +309,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
drawBufferStates[colorAttachment] != GL_NONE) drawBufferStates[colorAttachment] != GL_NONE)
{ {
RenderTargetD3D *drawRenderTarget = nullptr; RenderTargetD3D *drawRenderTarget = nullptr;
error = drawBuffer.getRenderTarget(&drawRenderTarget); ANGLE_TRY(drawBuffer.getRenderTarget(&drawRenderTarget));
if (error.isError())
{
return error;
}
ASSERT(drawRenderTarget); ASSERT(drawRenderTarget);
const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer); const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
...@@ -404,13 +330,9 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea, ...@@ -404,13 +330,9 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
actualDestArea.height = -destArea.height; actualDestArea.height = -destArea.height;
} }
error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea, ANGLE_TRY(mRenderer->blitRenderbufferRect(
readRenderTarget, drawRenderTarget, filter, actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget, filter,
scissor, blitRenderTarget, false, false); scissor, blitRenderTarget, false, false));
if (error.isError())
{
return error;
}
} }
} }
} }
...@@ -421,39 +343,23 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea, ...@@ -421,39 +343,23 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
ASSERT(readBuffer); ASSERT(readBuffer);
RenderTargetD3D *readRenderTarget = nullptr; RenderTargetD3D *readRenderTarget = nullptr;
gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); ANGLE_TRY(readBuffer->getRenderTarget(&readRenderTarget));
if (error.isError())
{
return error;
}
ASSERT(readRenderTarget); ASSERT(readRenderTarget);
const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
ASSERT(drawBuffer); ASSERT(drawBuffer);
RenderTargetD3D *drawRenderTarget = nullptr; RenderTargetD3D *drawRenderTarget = nullptr;
error = drawBuffer->getRenderTarget(&drawRenderTarget); ANGLE_TRY(drawBuffer->getRenderTarget(&drawRenderTarget));
if (error.isError())
{
return error;
}
ASSERT(drawRenderTarget); ASSERT(drawRenderTarget);
error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor, ANGLE_TRY(mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget,
false, blitDepth, blitStencil); drawRenderTarget, filter, scissor, false,
if (error.isError()) blitDepth, blitStencil));
{
return error;
}
}
gl::Error error = invalidateSwizzles();
if (error.isError())
{
return error;
} }
return gl::Error(GL_NO_ERROR); ANGLE_TRY(invalidateSwizzles());
return gl::NoError();
} }
GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
......
...@@ -66,6 +66,7 @@ class Framebuffer11 : public FramebufferD3D, public angle::SignalReceiver ...@@ -66,6 +66,7 @@ class Framebuffer11 : public FramebufferD3D, public angle::SignalReceiver
const gl::Framebuffer *sourceFramebuffer) override; const gl::Framebuffer *sourceFramebuffer) override;
gl::Error invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const; gl::Error invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const;
gl::Error invalidateAttachment(const gl::FramebufferAttachment *attachment) const;
GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override;
......
...@@ -1498,16 +1498,14 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode) ...@@ -1498,16 +1498,14 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode)
// Applies the render target surface, depth stencil surface, viewport rectangle and // Applies the render target surface, depth stencil surface, viewport rectangle and
// scissor rectangle to the renderer // scissor rectangle to the renderer
gl::Framebuffer *framebufferObject = glState.getDrawFramebuffer(); gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
ASSERT(framebufferObject && ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->complete(data));
framebufferObject->getCachedStatus(data) == GL_FRAMEBUFFER_COMPLETE); ANGLE_TRY(applyRenderTarget(framebuffer));
ANGLE_TRY(applyRenderTarget(framebufferObject));
// Set the present path state // Set the present path state
const bool presentPathFastActive = auto firstColorAttachment = framebuffer->getFirstColorbuffer();
UsePresentPathFast(this, framebufferObject->getFirstColorbuffer()); const bool presentPathFastActive = UsePresentPathFast(this, firstColorAttachment);
mStateManager.updatePresentPath(presentPathFastActive, mStateManager.updatePresentPath(presentPathFastActive, firstColorAttachment);
framebufferObject->getFirstColorbuffer());
// Setting viewport state // Setting viewport state
mStateManager.setViewport(&data.getCaps(), glState.getViewport(), glState.getNearPlane(), mStateManager.setViewport(&data.getCaps(), glState.getViewport(), glState.getNearPlane(),
...@@ -1517,7 +1515,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode) ...@@ -1517,7 +1515,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode)
mStateManager.setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); mStateManager.setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
// Applying rasterizer state to D3D11 device // Applying rasterizer state to D3D11 device
int samples = framebufferObject->getCachedSamples(data); int samples = framebuffer->getSamples(data);
gl::RasterizerState rasterizer = glState.getRasterizerState(); gl::RasterizerState rasterizer = glState.getRasterizerState();
rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.pointDrawMode = (drawMode == GL_POINTS);
rasterizer.multiSample = (samples != 0); rasterizer.multiSample = (samples != 0);
...@@ -1526,7 +1524,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode) ...@@ -1526,7 +1524,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode)
// Setting blend state // Setting blend state
unsigned int mask = GetBlendSampleMask(data, samples); unsigned int mask = GetBlendSampleMask(data, samples);
ANGLE_TRY(mStateManager.setBlendState(framebufferObject, glState.getBlendState(), ANGLE_TRY(mStateManager.setBlendState(framebuffer, glState.getBlendState(),
glState.getBlendColor(), mask)); glState.getBlendColor(), mask));
// Setting depth stencil state // Setting depth stencil state
......
...@@ -893,11 +893,10 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode) ...@@ -893,11 +893,10 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode)
// Applies the render target surface, depth stencil surface, viewport rectangle and // Applies the render target surface, depth stencil surface, viewport rectangle and
// scissor rectangle to the renderer // scissor rectangle to the renderer
const gl::Framebuffer *framebufferObject = glState.getDrawFramebuffer(); gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
ASSERT(framebufferObject && ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->complete(data));
framebufferObject->getCachedStatus(data) == GL_FRAMEBUFFER_COMPLETE);
ANGLE_TRY(applyRenderTarget(context, framebufferObject)); ANGLE_TRY(applyRenderTarget(context, framebuffer));
// Setting viewport state // Setting viewport state
setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode, setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode,
...@@ -907,7 +906,7 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode) ...@@ -907,7 +906,7 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode)
setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
// Setting blend, depth stencil, and rasterizer states // Setting blend, depth stencil, and rasterizer states
int samples = framebufferObject->getCachedSamples(data); int samples = framebuffer->getSamples(data);
gl::RasterizerState rasterizer = glState.getRasterizerState(); gl::RasterizerState rasterizer = glState.getRasterizerState();
rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.pointDrawMode = (drawMode == GL_POINTS);
rasterizer.multiSample = (samples != 0); rasterizer.multiSample = (samples != 0);
...@@ -927,8 +926,10 @@ void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) ...@@ -927,8 +926,10 @@ void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
gl::Error Renderer9::setBlendDepthRasterStates(const gl::ContextState &glData, GLenum drawMode) gl::Error Renderer9::setBlendDepthRasterStates(const gl::ContextState &glData, GLenum drawMode)
{ {
const auto &glState = glData.getState(); const auto &glState = glData.getState();
int samples = glState.getDrawFramebuffer()->getCachedSamples(glData); auto drawFramebuffer = glState.getDrawFramebuffer();
ASSERT(!drawFramebuffer->hasAnyDirtyBit());
int samples = drawFramebuffer->getSamples(glData);
gl::RasterizerState rasterizer = glState.getRasterizerState(); gl::RasterizerState rasterizer = glState.getRasterizerState();
rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.pointDrawMode = (drawMode == GL_POINTS);
rasterizer.multiSample = (samples != 0); rasterizer.multiSample = (samples != 0);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
// //
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle; using namespace angle;
...@@ -18,7 +19,7 @@ namespace ...@@ -18,7 +19,7 @@ namespace
class StateChangeTest : public ANGLETest class StateChangeTest : public ANGLETest
{ {
protected: protected:
StateChangeTest() : mFramebuffer(0) StateChangeTest()
{ {
setWindowWidth(64); setWindowWidth(64);
setWindowHeight(64); setWindowHeight(64);
...@@ -36,9 +37,8 @@ class StateChangeTest : public ANGLETest ...@@ -36,9 +37,8 @@ class StateChangeTest : public ANGLETest
ANGLETest::SetUp(); ANGLETest::SetUp();
glGenFramebuffers(1, &mFramebuffer); glGenFramebuffers(1, &mFramebuffer);
mTextures.resize(2, 0);
glGenTextures(2, mTextures.data()); glGenTextures(2, mTextures.data());
glGenRenderbuffers(1, &mRenderbuffer);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -57,11 +57,14 @@ class StateChangeTest : public ANGLETest ...@@ -57,11 +57,14 @@ class StateChangeTest : public ANGLETest
mTextures.clear(); mTextures.clear();
} }
glDeleteRenderbuffers(1, &mRenderbuffer);
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
GLuint mFramebuffer; GLuint mFramebuffer = 0;
std::vector<GLuint> mTextures; GLuint mRenderbuffer = 0;
std::vector<GLuint> mTextures = {0, 0};
}; };
class StateChangeTestES3 : public StateChangeTest class StateChangeTestES3 : public StateChangeTest
...@@ -141,6 +144,148 @@ TEST_P(StateChangeTest, CopyTexSubImage2DSync) ...@@ -141,6 +144,148 @@ TEST_P(StateChangeTest, CopyTexSubImage2DSync)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Test that Framebuffer completeness caching works when color attachments change.
TEST_P(StateChangeTest, FramebufferIncompleteColorAttachment)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture at color attachment 0 to be non-color-renderable.
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that caching works when color attachments change with TexStorage.
TEST_P(StateChangeTest, FramebufferIncompleteWithTexStorage)
{
if (!extensionEnabled("GL_EXT_texture_storage"))
{
std::cout << "Test skipped because TexStorage2DEXT not available." << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture at color attachment 0 to be non-color-renderable.
glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_ALPHA8_EXT, 16, 16);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that caching works when color attachments change with CompressedTexImage2D.
TEST_P(StateChangeTestES3, FramebufferIncompleteWithCompressedTex)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture at color attachment 0 to be non-color-renderable.
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_ETC2, 16, 16, 0, 64, nullptr);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that caching works when color attachments are deleted.
TEST_P(StateChangeTestES3, FramebufferIncompleteWhenAttachmentDeleted)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Delete the texture at color attachment 0.
glDeleteTextures(1, &mTextures[0]);
mTextures[0] = 0;
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that Framebuffer completeness caching works when depth attachments change.
TEST_P(StateChangeTest, FramebufferIncompleteDepthAttachment)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 16, 16);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mRenderbuffer);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture at color attachment 0 to be non-depth-renderable.
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that Framebuffer completeness caching works when stencil attachments change.
TEST_P(StateChangeTest, FramebufferIncompleteStencilAttachment)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 16, 16);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mRenderbuffer);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture at the stencil attachment to be non-stencil-renderable.
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Test that Framebuffer completeness caching works when depth-stencil attachments change.
TEST_P(StateChangeTest, FramebufferIncompleteDepthStencilAttachment)
{
if (getClientVersion() < 3 && !extensionEnabled("GL_OES_packed_depth_stencil"))
{
std::cout << "Test skipped because packed depth+stencil not availble." << std::endl;
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 16, 16);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mRenderbuffer);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Change the texture the depth-stencil attachment to be non-depth-stencil-renderable.
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
}
// Ensure that CopyTexSubImage3D syncs framebuffer changes. // Ensure that CopyTexSubImage3D syncs framebuffer changes.
TEST_P(StateChangeTestES3, CopyTexSubImage3DSync) TEST_P(StateChangeTestES3, CopyTexSubImage3DSync)
{ {
...@@ -240,6 +385,51 @@ TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync) ...@@ -240,6 +385,51 @@ TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests calling invalidate on incomplete framebuffers after switching attachments.
// Adapted partially from WebGL 2 test "renderbuffers/invalidate-framebuffer"
TEST_P(StateChangeTestES3, IncompleteRenderbufferAttachmentInvalidateSync)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
GLint samples = 0;
glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &samples);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
ASSERT_GL_NO_ERROR();
// invalidate the framebuffer when the attachment is incomplete: no storage allocated to the
// attached renderbuffer
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
GLenum attachments1[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1);
ASSERT_GL_NO_ERROR();
glRenderbufferStorageMultisample(GL_RENDERBUFFER, static_cast<GLsizei>(samples), GL_RGBA8,
getWindowWidth(), getWindowHeight());
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
GLRenderbuffer renderbuf;
glBindRenderbuffer(GL_RENDERBUFFER, renderbuf.get());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
renderbuf.get());
ASSERT_GL_NO_ERROR();
// invalidate the framebuffer when the attachment is incomplete: no storage allocated to the
// attached renderbuffer
// Note: the bug will only repro *without* a call to checkStatus before the invalidate.
GLenum attachments2[] = {GL_DEPTH_ATTACHMENT};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments2);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, static_cast<GLsizei>(samples),
GL_DEPTH_COMPONENT16, getWindowWidth(), getWindowHeight());
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
glClear(GL_DEPTH_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
}
class StateChangeRenderTest : public StateChangeTest class StateChangeRenderTest : public StateChangeTest
{ {
protected: protected:
......
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