зеркало из https://github.com/AvaloniaUI/angle.git
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/348957 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Родитель
73d417edc0
Коммит
362876b157
|
@ -24,22 +24,21 @@
|
|||
#include "libANGLE/renderer/RenderbufferImpl.h"
|
||||
#include "libANGLE/renderer/SurfaceImpl.h"
|
||||
|
||||
using namespace angle;
|
||||
|
||||
namespace gl
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId)
|
||||
|
||||
void BindResourceChannel(ChannelBinding *binding, FramebufferAttachmentObject *resource)
|
||||
{
|
||||
if (attachment->isAttached() &&
|
||||
attachment->type() == matchType &&
|
||||
attachment->id() == matchId)
|
||||
{
|
||||
attachment->detach();
|
||||
}
|
||||
}
|
||||
binding->bind(resource ? resource->getDirtyChannel() : nullptr);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FramebufferState::FramebufferState()
|
||||
: mLabel(),
|
||||
mColorAttachments(1),
|
||||
|
@ -171,16 +170,35 @@ bool FramebufferState::attachmentsHaveSameDimensions() const
|
|||
}
|
||||
|
||||
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(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)
|
||||
: 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);
|
||||
mDirtyColorAttachmentBindings.push_back(
|
||||
ChannelBinding(this, static_cast<SignalToken>(DIRTY_BIT_COLOR_ATTACHMENT_0)));
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer()
|
||||
|
@ -210,13 +228,28 @@ void Framebuffer::detachRenderbuffer(GLuint renderbufferId)
|
|||
|
||||
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.mStencilAttachment, resourceType, resourceId);
|
||||
detachMatchingAttachment(&mState.mDepthAttachment, 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
|
||||
|
@ -397,6 +430,18 @@ GLenum Framebuffer::checkStatus(const ContextState &state)
|
|||
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;
|
||||
int samples = -1;
|
||||
bool missingAttachment = true;
|
||||
|
@ -644,7 +689,7 @@ Error Framebuffer::clear(rx::ContextImpl *context, GLbitfield mask)
|
|||
{
|
||||
if (context->getGLState().isRasterizerDiscardEnabled())
|
||||
{
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
return mImpl->clear(context, mask);
|
||||
|
@ -657,7 +702,7 @@ Error Framebuffer::clearBufferfv(rx::ContextImpl *context,
|
|||
{
|
||||
if (context->getGLState().isRasterizerDiscardEnabled())
|
||||
{
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
return mImpl->clearBufferfv(context, buffer, drawbuffer, values);
|
||||
|
@ -670,7 +715,7 @@ Error Framebuffer::clearBufferuiv(rx::ContextImpl *context,
|
|||
{
|
||||
if (context->getGLState().isRasterizerDiscardEnabled())
|
||||
{
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
return mImpl->clearBufferuiv(context, buffer, drawbuffer, values);
|
||||
|
@ -683,7 +728,7 @@ Error Framebuffer::clearBufferiv(rx::ContextImpl *context,
|
|||
{
|
||||
if (context->getGLState().isRasterizerDiscardEnabled())
|
||||
{
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
return mImpl->clearBufferiv(context, buffer, drawbuffer, values);
|
||||
|
@ -697,7 +742,7 @@ Error Framebuffer::clearBufferfi(rx::ContextImpl *context,
|
|||
{
|
||||
if (context->getGLState().isRasterizerDiscardEnabled())
|
||||
{
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
return mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
|
||||
|
@ -719,11 +764,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context,
|
|||
GLenum type,
|
||||
GLvoid *pixels) const
|
||||
{
|
||||
Error error = mImpl->readPixels(context, area, format, type, pixels);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels));
|
||||
|
||||
Buffer *unpackBuffer = context->getGLState().getUnpackState().pixelBuffer.get();
|
||||
if (unpackBuffer)
|
||||
|
@ -731,7 +772,7 @@ Error Framebuffer::readPixels(rx::ContextImpl *context,
|
|||
unpackBuffer->onPixelUnpack();
|
||||
}
|
||||
|
||||
return Error(GL_NO_ERROR);
|
||||
return NoError();
|
||||
}
|
||||
|
||||
Error Framebuffer::blit(rx::ContextImpl *context,
|
||||
|
@ -745,16 +786,15 @@ Error Framebuffer::blit(rx::ContextImpl *context,
|
|||
|
||||
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
|
||||
// in this case return the first nonzero sample size
|
||||
for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
|
||||
// For a complete framebuffer, all attachments must have the same sample count.
|
||||
// In this case return the first nonzero sample size.
|
||||
const auto *firstColorAttachment = mState.getFirstColorAttachment();
|
||||
if (firstColorAttachment)
|
||||
{
|
||||
if (colorAttachment.isAttached())
|
||||
{
|
||||
return colorAttachment.getSamples();
|
||||
}
|
||||
ASSERT(firstColorAttachment->isAttached());
|
||||
return firstColorAttachment->getSamples();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,6 +831,8 @@ void Framebuffer::setAttachment(GLenum type,
|
|||
mState.mStencilAttachment.attach(type, binding, textureIndex, attachmentObj);
|
||||
mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
|
||||
mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
|
||||
BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
|
||||
BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -800,22 +842,26 @@ void Framebuffer::setAttachment(GLenum type,
|
|||
case GL_DEPTH_ATTACHMENT:
|
||||
mState.mDepthAttachment.attach(type, binding, textureIndex, resource);
|
||||
mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT);
|
||||
break;
|
||||
BindResourceChannel(&mDirtyDepthAttachmentBinding, resource);
|
||||
break;
|
||||
case GL_STENCIL:
|
||||
case GL_STENCIL_ATTACHMENT:
|
||||
mState.mStencilAttachment.attach(type, binding, textureIndex, resource);
|
||||
mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT);
|
||||
break;
|
||||
BindResourceChannel(&mDirtyStencilAttachmentBinding, resource);
|
||||
break;
|
||||
case GL_BACK:
|
||||
mState.mColorAttachments[0].attach(type, binding, textureIndex, resource);
|
||||
mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0);
|
||||
break;
|
||||
// No need for a resource binding for the default FBO, it's always complete.
|
||||
break;
|
||||
default:
|
||||
{
|
||||
size_t colorIndex = binding - GL_COLOR_ATTACHMENT0;
|
||||
ASSERT(colorIndex < mState.mColorAttachments.size());
|
||||
mState.mColorAttachments[colorIndex].attach(type, binding, textureIndex, resource);
|
||||
mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
|
||||
BindResourceChannel(&mDirtyColorAttachmentBindings[colorIndex], resource);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -827,27 +873,25 @@ void Framebuffer::resetAttachment(GLenum binding)
|
|||
setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr);
|
||||
}
|
||||
|
||||
void Framebuffer::syncState() const
|
||||
void Framebuffer::syncState()
|
||||
{
|
||||
if (mDirtyBits.any())
|
||||
{
|
||||
mImpl->syncState(mDirtyBits);
|
||||
mDirtyBits.reset();
|
||||
mCachedStatus.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int Framebuffer::getCachedSamples(const ContextState &state) const
|
||||
void Framebuffer::signal(SignalToken token)
|
||||
{
|
||||
// TODO(jmadill): Framebuffer samples caching.
|
||||
ASSERT(mDirtyBits.none());
|
||||
return const_cast<Framebuffer *>(this)->getSamples(state);
|
||||
// TOOD(jmadill): Make this only update individual attachments to do less work.
|
||||
mCachedStatus.reset();
|
||||
}
|
||||
|
||||
GLenum Framebuffer::getCachedStatus(const ContextState &state) const
|
||||
bool Framebuffer::complete(const ContextState &state)
|
||||
{
|
||||
// TODO(jmadill): Framebuffer status caching.
|
||||
ASSERT(mDirtyBits.none());
|
||||
return const_cast<Framebuffer *>(this)->checkStatus(state);
|
||||
return (checkStatus(state) == GL_FRAMEBUFFER_COMPLETE);
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "common/Optional.h"
|
||||
#include "common/angleutils.h"
|
||||
#include "libANGLE/Constants.h"
|
||||
#include "libANGLE/Debug.h"
|
||||
#include "libANGLE/Error.h"
|
||||
#include "libANGLE/FramebufferAttachment.h"
|
||||
#include "libANGLE/RefCountObject.h"
|
||||
#include "libANGLE/signal_utils.h"
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
@ -86,7 +88,7 @@ class FramebufferState final : angle::NonCopyable
|
|||
GLenum mReadBufferState;
|
||||
};
|
||||
|
||||
class Framebuffer final : public LabeledObject
|
||||
class Framebuffer final : public LabeledObject, public angle::SignalReceiver
|
||||
{
|
||||
public:
|
||||
Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id);
|
||||
|
@ -140,10 +142,8 @@ class Framebuffer final : public LabeledObject
|
|||
int getSamples(const ContextState &state);
|
||||
GLenum checkStatus(const ContextState &state);
|
||||
|
||||
// These methods do not change any state.
|
||||
// TODO(jmadill): Remove ContextState parameter when able.
|
||||
int getCachedSamples(const ContextState &state) const;
|
||||
GLenum getCachedStatus(const ContextState &state) const;
|
||||
// Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE.
|
||||
bool complete(const ContextState &state);
|
||||
|
||||
bool hasValidDepthStencil() const;
|
||||
|
||||
|
@ -200,19 +200,31 @@ class Framebuffer final : public LabeledObject
|
|||
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
|
||||
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 detachMatchingAttachment(FramebufferAttachment *attachment,
|
||||
GLenum matchType,
|
||||
GLuint matchId,
|
||||
size_t dirtyBit);
|
||||
GLenum checkStatusImpl(const ContextState &state);
|
||||
|
||||
FramebufferState mState;
|
||||
rx::FramebufferImpl *mImpl;
|
||||
GLuint mId;
|
||||
|
||||
// TODO(jmadill): See if we can make this non-mutable.
|
||||
mutable DirtyBits mDirtyBits;
|
||||
Optional<GLenum> mCachedStatus;
|
||||
std::vector<angle::ChannelBinding> mDirtyColorAttachmentBindings;
|
||||
angle::ChannelBinding mDirtyDepthAttachmentBinding;
|
||||
angle::ChannelBinding mDirtyStencilAttachmentBinding;
|
||||
|
||||
DirtyBits mDirtyBits;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace gl
|
||||
|
||||
#endif // LIBANGLE_FRAMEBUFFER_H_
|
||||
|
|
|
@ -233,4 +233,9 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget(
|
|||
return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut);
|
||||
}
|
||||
|
||||
angle::BroadcastChannel *FramebufferAttachmentObject::getDirtyChannel()
|
||||
{
|
||||
return &mDirtyChannel;
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "libANGLE/angletypes.h"
|
||||
#include "libANGLE/Error.h"
|
||||
#include "libANGLE/ImageIndex.h"
|
||||
#include "libANGLE/signal_utils.h"
|
||||
|
||||
namespace egl
|
||||
{
|
||||
|
@ -165,8 +166,12 @@ class FramebufferAttachmentObject
|
|||
Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target,
|
||||
rx::FramebufferAttachmentRenderTarget **rtOut) const;
|
||||
|
||||
angle::BroadcastChannel *getDirtyChannel();
|
||||
|
||||
protected:
|
||||
virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
|
||||
|
||||
angle::BroadcastChannel mDirtyChannel;
|
||||
};
|
||||
|
||||
inline Extents FramebufferAttachment::getSize() const
|
||||
|
|
|
@ -49,47 +49,39 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh
|
|||
{
|
||||
orphanImages();
|
||||
|
||||
Error error = mRenderbuffer->setStorage(internalformat, width, height);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderbuffer->setStorage(internalformat, width, height));
|
||||
|
||||
mWidth = static_cast<GLsizei>(width);
|
||||
mHeight = static_cast<GLsizei>(height);
|
||||
mInternalFormat = internalformat;
|
||||
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)
|
||||
{
|
||||
orphanImages();
|
||||
|
||||
Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderbuffer->setStorageMultisample(samples, internalformat, width, height));
|
||||
|
||||
mWidth = static_cast<GLsizei>(width);
|
||||
mHeight = static_cast<GLsizei>(height);
|
||||
mInternalFormat = internalformat;
|
||||
mSamples = static_cast<GLsizei>(samples);
|
||||
|
||||
return Error(GL_NO_ERROR);
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
|
||||
{
|
||||
orphanImages();
|
||||
|
||||
Error error = mRenderbuffer->setStorageEGLImageTarget(image);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderbuffer->setStorageEGLImageTarget(image));
|
||||
|
||||
setTargetImage(image);
|
||||
|
||||
|
@ -98,7 +90,9 @@ Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
|
|||
mInternalFormat = image->getInternalFormat();
|
||||
mSamples = 0;
|
||||
|
||||
return Error(GL_NO_ERROR);
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
rx::RenderbufferImpl *Renderbuffer::getImplementation()
|
||||
|
@ -181,4 +175,4 @@ Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /*
|
|||
{
|
||||
return Extents(mWidth, mHeight, 1);
|
||||
}
|
||||
}
|
||||
} // namespace gl
|
||||
|
|
|
@ -779,17 +779,14 @@ Error Texture::setImage(const PixelUnpackState &unpackState,
|
|||
releaseTexImageInternal();
|
||||
orphanImages();
|
||||
|
||||
Error error =
|
||||
mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(
|
||||
mTexture->setImage(target, level, internalFormat, size, format, type, unpackState, pixels));
|
||||
|
||||
mState.setImageDesc(target, level,
|
||||
ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return Error(GL_NO_ERROR);
|
||||
return NoError();
|
||||
}
|
||||
|
||||
Error Texture::setSubImage(const PixelUnpackState &unpackState,
|
||||
|
@ -820,17 +817,14 @@ Error Texture::setCompressedImage(const PixelUnpackState &unpackState,
|
|||
releaseTexImageInternal();
|
||||
orphanImages();
|
||||
|
||||
Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpackState,
|
||||
imageSize, pixels);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mTexture->setCompressedImage(target, level, internalFormat, size, unpackState,
|
||||
imageSize, pixels));
|
||||
|
||||
mState.setImageDesc(target, level,
|
||||
ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return Error(GL_NO_ERROR);
|
||||
return NoError();
|
||||
}
|
||||
|
||||
Error Texture::setCompressedSubImage(const PixelUnpackState &unpackState,
|
||||
|
@ -858,17 +852,14 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre
|
|||
releaseTexImageInternal();
|
||||
orphanImages();
|
||||
|
||||
Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mTexture->copyImage(target, level, sourceArea, internalFormat, source));
|
||||
|
||||
mState.setImageDesc(target, level,
|
||||
ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
|
||||
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,
|
||||
|
@ -888,17 +879,15 @@ Error Texture::setStorage(GLenum target, GLsizei levels, GLenum internalFormat,
|
|||
releaseTexImageInternal();
|
||||
orphanImages();
|
||||
|
||||
Error error = mTexture->setStorage(target, levels, internalFormat, size);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mTexture->setStorage(target, levels, internalFormat, size));
|
||||
|
||||
mState.mImmutableFormat = true;
|
||||
mState.mImmutableLevels = static_cast<GLuint>(levels);
|
||||
mState.clearImageDescs();
|
||||
mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, internalFormat);
|
||||
return Error(GL_NO_ERROR);
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
Error Texture::generateMipmap()
|
||||
|
@ -926,6 +915,8 @@ Error Texture::generateMipmap()
|
|||
baseImageInfo.internalFormat);
|
||||
}
|
||||
|
||||
mDirtyChannel.signal();
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
|
@ -946,6 +937,7 @@ void Texture::bindTexImageFromSurface(egl::Surface *surface)
|
|||
Extents size(surface->getWidth(), surface->getHeight(), 1);
|
||||
ImageDesc desc(size, surface->getConfig()->renderTargetFormat);
|
||||
mState.setImageDesc(mState.mTarget, 0, desc);
|
||||
mDirtyChannel.signal();
|
||||
}
|
||||
|
||||
void Texture::releaseTexImageFromSurface()
|
||||
|
@ -957,6 +949,7 @@ void Texture::releaseTexImageFromSurface()
|
|||
// Erase the image info for level 0
|
||||
ASSERT(mState.mTarget == GL_TEXTURE_2D);
|
||||
mState.clearImageDesc(mState.mTarget, 0);
|
||||
mDirtyChannel.signal();
|
||||
}
|
||||
|
||||
void Texture::bindStream(egl::Stream *stream)
|
||||
|
@ -984,6 +977,7 @@ void Texture::acquireImageFromStream(const egl::Stream::GLTextureDescription &de
|
|||
|
||||
Extents size(desc.width, desc.height, 1);
|
||||
mState.setImageDesc(mState.mTarget, 0, ImageDesc(size, desc.internalFormat));
|
||||
mDirtyChannel.signal();
|
||||
}
|
||||
|
||||
void Texture::releaseImageFromStream()
|
||||
|
@ -993,6 +987,7 @@ void Texture::releaseImageFromStream()
|
|||
|
||||
// Set to incomplete
|
||||
mState.clearImageDesc(mState.mTarget, 0);
|
||||
mDirtyChannel.signal();
|
||||
}
|
||||
|
||||
void Texture::releaseTexImageInternal()
|
||||
|
@ -1016,11 +1011,7 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
|
|||
releaseTexImageInternal();
|
||||
orphanImages();
|
||||
|
||||
Error error = mTexture->setEGLImageTarget(target, imageTarget);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mTexture->setEGLImageTarget(target, imageTarget));
|
||||
|
||||
setTargetImage(imageTarget);
|
||||
|
||||
|
@ -1031,8 +1022,9 @@ Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
|
|||
|
||||
mState.clearImageDescs();
|
||||
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
|
||||
|
@ -1070,4 +1062,4 @@ rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
|
|||
{
|
||||
return mTexture;
|
||||
}
|
||||
}
|
||||
} // namespace gl
|
||||
|
|
|
@ -56,19 +56,14 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal
|
|||
}
|
||||
|
||||
RenderTargetD3D *newRT = NULL;
|
||||
gl::Error error =
|
||||
mRenderer->createRenderTarget(static_cast<int>(width), static_cast<int>(height),
|
||||
creationFormat, static_cast<GLsizei>(samples), &newRT);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderer->createRenderTarget(static_cast<int>(width), static_cast<int>(height),
|
||||
creationFormat, static_cast<GLsizei>(samples), &newRT));
|
||||
|
||||
SafeDelete(mRenderTarget);
|
||||
mImage = nullptr;
|
||||
mRenderTarget = newRT;
|
||||
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
|
||||
|
@ -76,7 +71,7 @@ gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
|
|||
mImage = GetImplAs<EGLImageD3D>(image);
|
||||
SafeDelete(mRenderTarget);
|
||||
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget)
|
||||
|
@ -88,7 +83,7 @@ gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget)
|
|||
else
|
||||
{
|
||||
*outRenderTarget = mRenderTarget;
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme
|
|||
TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
|
||||
|
||||
TextureStorage *texStorage = nullptr;
|
||||
gl::Error error = textureD3D->getNativeTexture(&texStorage);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(textureD3D->getNativeTexture(&texStorage));
|
||||
|
||||
if (texStorage)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -99,33 +95,19 @@ gl::Error Framebuffer11::invalidateSwizzles() const
|
|||
{
|
||||
if (colorAttachment.isAttached())
|
||||
{
|
||||
gl::Error error = InvalidateAttachmentSwizzles(&colorAttachment);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(InvalidateAttachmentSwizzles(&colorAttachment));
|
||||
}
|
||||
}
|
||||
|
||||
gl::Error error = InvalidateAttachmentSwizzles(mState.getDepthAttachment());
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(InvalidateAttachmentSwizzles(mState.getDepthAttachment()));
|
||||
ANGLE_TRY(InvalidateAttachmentSwizzles(mState.getStencilAttachment()));
|
||||
|
||||
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)
|
||||
{
|
||||
Clear11 *clearer = mRenderer->getClearer();
|
||||
gl::Error error(GL_NO_ERROR);
|
||||
|
||||
const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment();
|
||||
if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
|
||||
|
@ -139,25 +121,16 @@ gl::Error Framebuffer11::clearImpl(ContextImpl *context, const ClearParameters &
|
|||
presentPathFastClearParams.scissor.y = framebufferSize.height -
|
||||
presentPathFastClearParams.scissor.y -
|
||||
presentPathFastClearParams.scissor.height;
|
||||
error = clearer->clearFramebuffer(presentPathFastClearParams, mState);
|
||||
ANGLE_TRY(clearer->clearFramebuffer(presentPathFastClearParams, mState));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = clearer->clearFramebuffer(clearParams, mState);
|
||||
ANGLE_TRY(clearer->clearFramebuffer(clearParams, mState));
|
||||
}
|
||||
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(invalidateSwizzles());
|
||||
|
||||
error = 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)
|
||||
|
@ -177,7 +150,7 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments,
|
|||
if (!deviceContext1)
|
||||
{
|
||||
// DiscardView() is only supported on ID3D11DeviceContext1
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
bool foundDepth = false;
|
||||
|
@ -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) ||
|
||||
(attachments[i] == GL_COLOR));
|
||||
|
||||
RenderTarget11 *renderTarget = nullptr;
|
||||
ID3D11View *colorView = nullptr;
|
||||
gl::Error error(GL_NO_ERROR);
|
||||
size_t colorAttachmentID = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
size_t colorIndex =
|
||||
(attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0));
|
||||
auto colorAttachment = mState.getColorAttachment(colorIndex);
|
||||
ANGLE_TRY(invalidateAttachment(colorAttachment));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -268,51 +214,39 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments,
|
|||
|
||||
if (discardDepth && mState.getDepthAttachment())
|
||||
{
|
||||
RenderTarget11 *renderTarget = nullptr;
|
||||
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);
|
||||
}
|
||||
ANGLE_TRY(invalidateAttachment(mState.getDepthAttachment()));
|
||||
}
|
||||
|
||||
if (discardStencil && mState.getStencilAttachment())
|
||||
{
|
||||
RenderTarget11 *renderTarget = nullptr;
|
||||
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);
|
||||
}
|
||||
ANGLE_TRY(invalidateAttachment(mState.getStencilAttachment()));
|
||||
}
|
||||
|
||||
return gl::Error(GL_NO_ERROR);
|
||||
return gl::NoError();
|
||||
}
|
||||
|
||||
gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &)
|
||||
{
|
||||
// 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,
|
||||
|
@ -361,11 +295,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
|
|||
ASSERT(readBuffer);
|
||||
|
||||
RenderTargetD3D *readRenderTarget = nullptr;
|
||||
gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(readBuffer->getRenderTarget(&readRenderTarget));
|
||||
ASSERT(readRenderTarget);
|
||||
|
||||
const auto &colorAttachments = mState.getColorAttachments();
|
||||
|
@ -379,11 +309,7 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
|
|||
drawBufferStates[colorAttachment] != GL_NONE)
|
||||
{
|
||||
RenderTargetD3D *drawRenderTarget = nullptr;
|
||||
error = drawBuffer.getRenderTarget(&drawRenderTarget);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(drawBuffer.getRenderTarget(&drawRenderTarget));
|
||||
ASSERT(drawRenderTarget);
|
||||
|
||||
const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
|
||||
|
@ -404,13 +330,9 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
|
|||
actualDestArea.height = -destArea.height;
|
||||
}
|
||||
|
||||
error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea,
|
||||
readRenderTarget, drawRenderTarget, filter,
|
||||
scissor, blitRenderTarget, false, false);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderer->blitRenderbufferRect(
|
||||
actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget, filter,
|
||||
scissor, blitRenderTarget, false, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,39 +343,23 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
|
|||
ASSERT(readBuffer);
|
||||
|
||||
RenderTargetD3D *readRenderTarget = nullptr;
|
||||
gl::Error error = readBuffer->getRenderTarget(&readRenderTarget);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(readBuffer->getRenderTarget(&readRenderTarget));
|
||||
ASSERT(readRenderTarget);
|
||||
|
||||
const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
|
||||
ASSERT(drawBuffer);
|
||||
|
||||
RenderTargetD3D *drawRenderTarget = nullptr;
|
||||
error = drawBuffer->getRenderTarget(&drawRenderTarget);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(drawBuffer->getRenderTarget(&drawRenderTarget));
|
||||
ASSERT(drawRenderTarget);
|
||||
|
||||
error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor,
|
||||
false, blitDepth, blitStencil);
|
||||
if (error.isError())
|
||||
{
|
||||
return error;
|
||||
}
|
||||
ANGLE_TRY(mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget,
|
||||
drawRenderTarget, filter, scissor, false,
|
||||
blitDepth, blitStencil));
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -66,6 +66,7 @@ class Framebuffer11 : public FramebufferD3D, public angle::SignalReceiver
|
|||
const gl::Framebuffer *sourceFramebuffer) override;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
// scissor rectangle to the renderer
|
||||
gl::Framebuffer *framebufferObject = glState.getDrawFramebuffer();
|
||||
ASSERT(framebufferObject &&
|
||||
framebufferObject->getCachedStatus(data) == GL_FRAMEBUFFER_COMPLETE);
|
||||
ANGLE_TRY(applyRenderTarget(framebufferObject));
|
||||
gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
|
||||
ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->complete(data));
|
||||
ANGLE_TRY(applyRenderTarget(framebuffer));
|
||||
|
||||
// Set the present path state
|
||||
const bool presentPathFastActive =
|
||||
UsePresentPathFast(this, framebufferObject->getFirstColorbuffer());
|
||||
mStateManager.updatePresentPath(presentPathFastActive,
|
||||
framebufferObject->getFirstColorbuffer());
|
||||
auto firstColorAttachment = framebuffer->getFirstColorbuffer();
|
||||
const bool presentPathFastActive = UsePresentPathFast(this, firstColorAttachment);
|
||||
mStateManager.updatePresentPath(presentPathFastActive, firstColorAttachment);
|
||||
|
||||
// Setting viewport state
|
||||
mStateManager.setViewport(&data.getCaps(), glState.getViewport(), glState.getNearPlane(),
|
||||
|
@ -1517,7 +1515,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode)
|
|||
mStateManager.setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
|
||||
|
||||
// Applying rasterizer state to D3D11 device
|
||||
int samples = framebufferObject->getCachedSamples(data);
|
||||
int samples = framebuffer->getSamples(data);
|
||||
gl::RasterizerState rasterizer = glState.getRasterizerState();
|
||||
rasterizer.pointDrawMode = (drawMode == GL_POINTS);
|
||||
rasterizer.multiSample = (samples != 0);
|
||||
|
@ -1526,7 +1524,7 @@ gl::Error Renderer11::updateState(const gl::ContextState &data, GLenum drawMode)
|
|||
|
||||
// Setting blend state
|
||||
unsigned int mask = GetBlendSampleMask(data, samples);
|
||||
ANGLE_TRY(mStateManager.setBlendState(framebufferObject, glState.getBlendState(),
|
||||
ANGLE_TRY(mStateManager.setBlendState(framebuffer, glState.getBlendState(),
|
||||
glState.getBlendColor(), mask));
|
||||
|
||||
// Setting depth stencil state
|
||||
|
|
|
@ -893,11 +893,10 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode)
|
|||
|
||||
// Applies the render target surface, depth stencil surface, viewport rectangle and
|
||||
// scissor rectangle to the renderer
|
||||
const gl::Framebuffer *framebufferObject = glState.getDrawFramebuffer();
|
||||
ASSERT(framebufferObject &&
|
||||
framebufferObject->getCachedStatus(data) == GL_FRAMEBUFFER_COMPLETE);
|
||||
gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
|
||||
ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->complete(data));
|
||||
|
||||
ANGLE_TRY(applyRenderTarget(context, framebufferObject));
|
||||
ANGLE_TRY(applyRenderTarget(context, framebuffer));
|
||||
|
||||
// Setting viewport state
|
||||
setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode,
|
||||
|
@ -907,7 +906,7 @@ gl::Error Renderer9::updateState(Context9 *context, GLenum drawMode)
|
|||
setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
|
||||
|
||||
// Setting blend, depth stencil, and rasterizer states
|
||||
int samples = framebufferObject->getCachedSamples(data);
|
||||
int samples = framebuffer->getSamples(data);
|
||||
gl::RasterizerState rasterizer = glState.getRasterizerState();
|
||||
rasterizer.pointDrawMode = (drawMode == GL_POINTS);
|
||||
rasterizer.multiSample = (samples != 0);
|
||||
|
@ -927,8 +926,10 @@ void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
|
|||
|
||||
gl::Error Renderer9::setBlendDepthRasterStates(const gl::ContextState &glData, GLenum drawMode)
|
||||
{
|
||||
const auto &glState = glData.getState();
|
||||
int samples = glState.getDrawFramebuffer()->getCachedSamples(glData);
|
||||
const auto &glState = glData.getState();
|
||||
auto drawFramebuffer = glState.getDrawFramebuffer();
|
||||
ASSERT(!drawFramebuffer->hasAnyDirtyBit());
|
||||
int samples = drawFramebuffer->getSamples(glData);
|
||||
gl::RasterizerState rasterizer = glState.getRasterizerState();
|
||||
rasterizer.pointDrawMode = (drawMode == GL_POINTS);
|
||||
rasterizer.multiSample = (samples != 0);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//
|
||||
|
||||
#include "test_utils/ANGLETest.h"
|
||||
#include "test_utils/gl_raii.h"
|
||||
|
||||
using namespace angle;
|
||||
|
||||
|
@ -18,7 +19,7 @@ namespace
|
|||
class StateChangeTest : public ANGLETest
|
||||
{
|
||||
protected:
|
||||
StateChangeTest() : mFramebuffer(0)
|
||||
StateChangeTest()
|
||||
{
|
||||
setWindowWidth(64);
|
||||
setWindowHeight(64);
|
||||
|
@ -36,9 +37,8 @@ class StateChangeTest : public ANGLETest
|
|||
ANGLETest::SetUp();
|
||||
|
||||
glGenFramebuffers(1, &mFramebuffer);
|
||||
|
||||
mTextures.resize(2, 0);
|
||||
glGenTextures(2, mTextures.data());
|
||||
glGenRenderbuffers(1, &mRenderbuffer);
|
||||
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
@ -57,11 +57,14 @@ class StateChangeTest : public ANGLETest
|
|||
mTextures.clear();
|
||||
}
|
||||
|
||||
glDeleteRenderbuffers(1, &mRenderbuffer);
|
||||
|
||||
ANGLETest::TearDown();
|
||||
}
|
||||
|
||||
GLuint mFramebuffer;
|
||||
std::vector<GLuint> mTextures;
|
||||
GLuint mFramebuffer = 0;
|
||||
GLuint mRenderbuffer = 0;
|
||||
std::vector<GLuint> mTextures = {0, 0};
|
||||
};
|
||||
|
||||
class StateChangeTestES3 : public StateChangeTest
|
||||
|
@ -141,6 +144,148 @@ TEST_P(StateChangeTest, CopyTexSubImage2DSync)
|
|||
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.
|
||||
TEST_P(StateChangeTestES3, CopyTexSubImage3DSync)
|
||||
{
|
||||
|
@ -240,6 +385,51 @@ TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync)
|
|||
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
|
||||
{
|
||||
protected:
|
||||
|
|
Загрузка…
Ссылка в новой задаче