Commit 888081d5 by Jamie Madill Committed by Commit Bot

D3D11: Refactor dependent Framebuffer state changes.

Previously, when a state change would cause a Texture to recreate its storage specific to D3D11, we would use a dependent notification from RenderTarget11 to Framebuffer11 to re-check internal dirty bits. In this new method, we instead set dirty bits on the gl::Frambuffer directly. This also means we use fewer internal objects for these notifications, because we share the same structures between the D3D11 back-end notifications and the top-level notifications we use for Robust init and Framebuffer completeness. This also allows us to get rid of one "if" that we check on every draw call in D3D11. This also introduces a dirty bits guard concept - a shadow set of dirty bits that is checked in dependent state changes to ensure that extra bits aren't set inside syncState. This also implements Framebuffer dirty bits for the D3D9 back-end. This has the side effect of cleaning up the "null colorbuffer" D3D9 workaround. Bug: angleproject:2372 Change-Id: Ie346d39030f4f6df583d735685b0babea4e745a8 Reviewed-on: https://chromium-review.googlesource.com/936691Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 92e4e079
......@@ -1773,7 +1773,7 @@ void Framebuffer::updateAttachment(const Context *context,
multiviewLayout, viewportOffsets);
mDirtyBits.set(dirtyBit);
mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
onDirtyBinding->bind(resource);
onDirtyBinding->bind(resource ? resource->getSubject() : nullptr);
}
void Framebuffer::resetAttachment(const Context *context, GLenum binding)
......@@ -1785,12 +1785,14 @@ void Framebuffer::syncState(const Context *context)
{
if (mDirtyBits.any())
{
mDirtyBitsGuard = mDirtyBits;
mImpl->syncState(context, mDirtyBits);
mDirtyBits.reset();
if (mId != 0)
{
mCachedStatus.reset();
}
mDirtyBitsGuard.reset();
}
}
......@@ -1798,6 +1800,14 @@ void Framebuffer::onSubjectStateChange(const Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{
if (message == angle::SubjectMessage::DEPENDENT_DIRTY_BITS)
{
ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(index));
mDirtyBits.set(index);
context->getGLState().setFramebufferDirty(this);
return;
}
// Only reset the cached status if this is not the default framebuffer. The default framebuffer
// will still use this channel to mark itself dirty.
if (mId != 0)
......
......@@ -391,6 +391,10 @@ class Framebuffer final : public LabeledObject, public angle::ObserverInterface
DirtyBits mDirtyBits;
// The dirty bits guard is checked when we get a dependent state change message. We verify that
// we don't set a dirty bit that isn't already set, when inside the dirty bits syncState.
Optional<DirtyBits> mDirtyBitsGuard;
// A cache of attached textures for quick validation of feedback loops.
mutable Optional<std::set<const FramebufferAttachmentObject *>> mAttachedTextures;
};
......
......@@ -353,6 +353,16 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget(
return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut);
}
void FramebufferAttachmentObject::onStateChange(const gl::Context *context) const
{
return getAttachmentImpl()->onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
}
angle::Subject *FramebufferAttachmentObject::getSubject() const
{
return getAttachmentImpl();
}
Error FramebufferAttachmentObject::initializeContents(const Context *context,
const ImageIndex &imageIndex)
{
......
......@@ -15,7 +15,6 @@
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h"
#include "libANGLE/ImageIndex.h"
#include "libANGLE/signal_utils.h"
namespace egl
{
......@@ -36,6 +35,11 @@ class FramebufferAttachmentRenderTarget : angle::NonCopyable
class FramebufferAttachmentObjectImpl;
}
namespace angle
{
class Subject;
} // namespace angle
namespace gl
{
class FramebufferAttachmentObject;
......@@ -180,7 +184,7 @@ class FramebufferAttachment final
};
// A base class for objects that FBO Attachments may point to.
class FramebufferAttachmentObject : public angle::Subject
class FramebufferAttachmentObject
{
public:
FramebufferAttachmentObject();
......@@ -206,6 +210,9 @@ class FramebufferAttachmentObject : public angle::Subject
Error initializeContents(const Context *context, const ImageIndex &imageIndex);
void onStateChange(const gl::Context *context) const;
angle::Subject *getSubject() const;
protected:
virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
};
......
......@@ -109,7 +109,7 @@ Error Renderbuffer::setStorage(const Context *context,
mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat),
0, InitState::MayNeedInit);
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
onStateChange(context);
return NoError();
}
......@@ -126,7 +126,7 @@ Error Renderbuffer::setStorageMultisample(const Context *context,
mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat),
static_cast<GLsizei>(samples), InitState::MayNeedInit);
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
onStateChange(context);
return NoError();
}
......@@ -140,7 +140,7 @@ Error Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image
mState.update(static_cast<GLsizei>(image->getWidth()), static_cast<GLsizei>(image->getHeight()),
Format(image->getFormat()), 0, image->sourceInitState());
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
onStateChange(context);
return NoError();
}
......
......@@ -2320,7 +2320,7 @@ void State::syncProgramTextures(const Context *context)
}
// Bind the texture unconditionally, to recieve completeness change notifications.
mCompleteTextureBindings[textureUnitIndex].bind(texture);
mCompleteTextureBindings[textureUnitIndex].bind(texture->getSubject());
mActiveTexturesMask.set(textureUnitIndex);
newActiveTextures.set(textureUnitIndex);
......@@ -2404,6 +2404,18 @@ void State::setObjectDirty(GLenum target)
}
}
void State::setFramebufferDirty(const Framebuffer *framebuffer) const
{
if (framebuffer == mReadFramebuffer)
{
mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
}
if (framebuffer == mDrawFramebuffer)
{
mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
}
}
void State::onProgramExecutableChange(Program *program)
{
// OpenGL Spec:
......
......@@ -444,6 +444,7 @@ class State : public angle::ObserverInterface, angle::NonCopyable
void syncDirtyObjects(const Context *context, const DirtyObjects &bitset);
void syncDirtyObject(const Context *context, GLenum target);
void setObjectDirty(GLenum target);
void setFramebufferDirty(const Framebuffer *framebuffer) const;
// This actually clears the current value dirty bits.
// TODO(jmadill): Pass mutable dirty bits into Impl.
......@@ -601,7 +602,7 @@ class State : public angle::ObserverInterface, angle::NonCopyable
bool mProgramBinaryCacheEnabled;
DirtyBits mDirtyBits;
DirtyObjects mDirtyObjects;
mutable DirtyObjects mDirtyObjects;
mutable AttributesMask mDirtyCurrentValues;
};
......
......@@ -156,7 +156,7 @@ void Surface::postSwap(const gl::Context *context)
if (mRobustResourceInitialization && mSwapBehavior != EGL_BUFFER_PRESERVED)
{
mInitState = gl::InitState::MayNeedInit;
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
onStateChange(context);
}
}
......
......@@ -916,7 +916,7 @@ egl::Stream *Texture::getBoundStream() const
void Texture::signalDirty(const Context *context, InitState initState)
{
mState.mInitState = initState;
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
onStateChange(context);
invalidateCompletenessCache();
}
......
......@@ -12,11 +12,12 @@
#define LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/signal_utils.h"
namespace rx
{
class FramebufferAttachmentObjectImpl : angle::NonCopyable
class FramebufferAttachmentObjectImpl : public angle::Subject
{
public:
FramebufferAttachmentObjectImpl() {}
......
......@@ -80,7 +80,10 @@ gl::Error EGLImageD3D::copyToLocalRendertarget(const gl::Context *context)
ANGLE_TRY(getRenderTarget(context, &curRenderTarget));
// This only currently applies do D3D11, where it invalidates FBOs with this Image attached.
curRenderTarget->signalDirty(context);
for (egl::ImageSibling *target : mState.targets)
{
target->getSubject()->onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
}
return mRenderer->createRenderTargetCopy(curRenderTarget, &mRenderTarget);
}
......
......@@ -34,9 +34,6 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget
virtual unsigned int getSerial() const;
static unsigned int issueSerials(unsigned int count);
// Only currently applies to D3D11.
virtual void signalDirty(const gl::Context *context) {}
private:
const unsigned int mSerial;
static unsigned int mCurrentSerial;
......
......@@ -112,9 +112,9 @@ gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::Context *context,
void RenderbufferD3D::deleteRenderTarget(const gl::Context *context)
{
onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
if (mRenderTarget)
{
mRenderTarget->signalDirty(context);
SafeDelete(mRenderTarget);
}
}
......
......@@ -653,6 +653,9 @@ gl::Error TextureD3D::releaseTexStorage(const gl::Context *context)
{
return gl::NoError();
}
onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
auto err = mTexStorage->onDestroy(context);
SafeDelete(mTexStorage);
return err;
......@@ -1249,6 +1252,8 @@ gl::Error TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *
mDirtyImages = false;
mImageArray[0]->markClean();
mTexStorage->setSubject(this);
return gl::NoError();
}
......@@ -1437,6 +1442,7 @@ gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget,
// TODO(geofflang): Determine if the texture creation succeeded
outStorage->reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height,
levels, hintLevelZeroOnly));
(*outStorage)->setSubject(this);
return gl::NoError();
}
......@@ -1456,6 +1462,8 @@ gl::Error TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
ANGLE_TRY(releaseTexStorage(context));
mTexStorage = newCompleteTexStorage;
mTexStorage->setSubject(this);
mDirtyImages = true;
return gl::NoError();
......
......@@ -23,6 +23,11 @@ struct Box;
struct PixelUnpackState;
} // namespace gl
namespace angle
{
class Subject;
} // namespace angle
namespace rx
{
class SwapChainD3D;
......@@ -32,7 +37,7 @@ class ImageD3D;
class TextureStorage : angle::NonCopyable
{
public:
TextureStorage() {}
TextureStorage() : mSubject(nullptr) {}
virtual ~TextureStorage() {}
virtual gl::Error onDestroy(const gl::Context *context);
......@@ -62,6 +67,12 @@ class TextureStorage : angle::NonCopyable
// This is a no-op for most implementations of TextureStorage. Some (e.g. TextureStorage11_2D) might override it.
virtual gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context,
bool useLevelZeroTexture);
// Only used for D3D11.
void setSubject(const angle::Subject *subject);
protected:
const angle::Subject *mSubject;
};
inline gl::Error TextureStorage::onDestroy(const gl::Context *context)
......@@ -75,6 +86,11 @@ inline gl::Error TextureStorage::useLevelZeroWorkaroundTexture(const gl::Context
return gl::NoError();
}
inline void TextureStorage::setSubject(const angle::Subject *subject)
{
mSubject = subject;
}
using TexStoragePointer = angle::UniqueObjectPointer<TextureStorage, gl::Context>;
} // namespace rx
......
......@@ -56,8 +56,7 @@ gl::Error MarkAttachmentsDirty(const gl::Context *context,
void UpdateCachedRenderTarget(const gl::Context *context,
const gl::FramebufferAttachment *attachment,
RenderTarget11 *&cachedRenderTarget,
angle::ObserverBinding *channelBinding)
RenderTarget11 *&cachedRenderTarget)
{
RenderTarget11 *newRenderTarget = nullptr;
if (attachment)
......@@ -71,24 +70,16 @@ void UpdateCachedRenderTarget(const gl::Context *context,
}
if (newRenderTarget != cachedRenderTarget)
{
channelBinding->bind(newRenderTarget);
cachedRenderTarget = newRenderTarget;
}
}
} // anonymous namespace
Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer)
: FramebufferD3D(data, renderer),
mRenderer(renderer),
mCachedDepthStencilRenderTarget(nullptr),
mDepthStencilRenderTargetDirty(this, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
: FramebufferD3D(data, renderer), mRenderer(renderer), mCachedDepthStencilRenderTarget(nullptr)
{
ASSERT(mRenderer != nullptr);
mCachedColorRenderTargets.fill(nullptr);
for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex)
{
mColorRenderTargetsDirty.emplace_back(this, colorIndex);
}
}
Framebuffer11::~Framebuffer11()
......@@ -390,23 +381,19 @@ GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *rende
void Framebuffer11::updateColorRenderTarget(const gl::Context *context, size_t colorIndex)
{
UpdateCachedRenderTarget(context, mState.getColorAttachment(colorIndex),
mCachedColorRenderTargets[colorIndex],
&mColorRenderTargetsDirty[colorIndex]);
mCachedColorRenderTargets[colorIndex]);
}
void Framebuffer11::updateDepthStencilRenderTarget(const gl::Context *context)
{
UpdateCachedRenderTarget(context, mState.getDepthOrStencilAttachment(),
mCachedDepthStencilRenderTarget, &mDepthStencilRenderTargetDirty);
mCachedDepthStencilRenderTarget);
}
void Framebuffer11::syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits)
{
const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits;
mInternalDirtyBits.reset();
for (auto dirtyBit : mergedDirtyBits)
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
......@@ -434,9 +421,6 @@ void Framebuffer11::syncState(const gl::Context *context,
}
}
// We should not have dirtied any additional state during our sync.
ASSERT(!mInternalDirtyBits.any());
FramebufferD3D::syncState(context, dirtyBits);
// Call this last to allow the state manager to take advantage of the cached render targets.
......@@ -449,27 +433,6 @@ void Framebuffer11::syncState(const gl::Context *context,
}
}
void Framebuffer11::onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{
if (index == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
{
// Stencil is redundant in this case.
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
mCachedDepthStencilRenderTarget = nullptr;
}
else
{
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + index);
mCachedColorRenderTargets[index] = nullptr;
}
// Notify the context we need to re-validate the RenderTarget.
// TODO(jmadill): Check that we're the active draw framebuffer.
mRenderer->getStateManager()->invalidateRenderTarget();
}
gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const
{
const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment();
......@@ -480,19 +443,8 @@ gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const
return gl::NoError();
}
bool Framebuffer11::hasAnyInternalDirtyBit() const
{
return mInternalDirtyBits.any();
}
void Framebuffer11::syncInternalState(const gl::Context *context)
{
syncState(context, gl::Framebuffer::DirtyBits());
}
RenderTarget11 *Framebuffer11::getFirstRenderTarget() const
{
ASSERT(mInternalDirtyBits.none());
for (auto *renderTarget : mCachedColorRenderTargets)
{
if (renderTarget)
......
......@@ -17,7 +17,7 @@ namespace rx
{
class Renderer11;
class Framebuffer11 : public FramebufferD3D, public angle::ObserverInterface
class Framebuffer11 : public FramebufferD3D
{
public:
Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer);
......@@ -38,7 +38,7 @@ class Framebuffer11 : public FramebufferD3D, public angle::ObserverInterface
void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override;
const RenderTargetArray &getCachedColorRenderTargets() const
const RenderTargetArray11 &getCachedColorRenderTargets() const
{
return mCachedColorRenderTargets;
}
......@@ -49,14 +49,6 @@ class Framebuffer11 : public FramebufferD3D, public angle::ObserverInterface
RenderTarget11 *getFirstRenderTarget() const;
bool hasAnyInternalDirtyBit() const;
void syncInternalState(const gl::Context *context);
// Observer implementation.
void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
private:
......@@ -93,15 +85,10 @@ class Framebuffer11 : public FramebufferD3D, public angle::ObserverInterface
void updateDepthStencilRenderTarget(const gl::Context *context);
Renderer11 *const mRenderer;
RenderTargetArray mCachedColorRenderTargets;
RenderTargetArray11 mCachedColorRenderTargets;
RenderTarget11 *mCachedDepthStencilRenderTarget;
std::vector<angle::ObserverBinding> mColorRenderTargetsDirty;
angle::ObserverBinding mDepthStencilRenderTargetDirty;
gl::Framebuffer::DirtyBits mInternalDirtyBits;
};
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_
......@@ -200,15 +200,6 @@ RenderTarget11::RenderTarget11(const d3d11::Format &formatSet) : mFormatSet(form
RenderTarget11::~RenderTarget11()
{
ASSERT(!hasObservers());
}
void RenderTarget11::signalDirty(const gl::Context *context)
{
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
// Clear the list. We can't do this in the receiver because it would mutate during iteration.
resetObservers();
}
TextureRenderTarget11::TextureRenderTarget11(d3d11::RenderTargetView &&rtv,
......
......@@ -20,7 +20,7 @@ namespace rx
class SwapChain11;
class Renderer11;
class RenderTarget11 : public RenderTargetD3D, public angle::Subject
class RenderTarget11 : public RenderTargetD3D
{
public:
RenderTarget11(const d3d11::Format &formatSet);
......@@ -34,8 +34,6 @@ class RenderTarget11 : public RenderTargetD3D, public angle::Subject
virtual unsigned int getSubresourceIndex() const = 0;
void signalDirty(const gl::Context *context) override;
const d3d11::Format &getFormatSet() const { return mFormatSet; }
protected:
......
......@@ -1751,7 +1751,6 @@ gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Frameb
// this will not report any gl error but will cause the calling method to return.
if (framebuffer->id() == 0)
{
ASSERT(!framebuffer11->hasAnyInternalDirtyBit());
const gl::Extents &size = framebuffer->getFirstColorbuffer()->getSize();
if (size.width == 0 || size.height == 0)
{
......@@ -1983,12 +1982,6 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
ANGLE_TRY(framebuffer11->markAttachmentsDirty(context));
if (framebuffer11->hasAnyInternalDirtyBit())
{
ASSERT(framebuffer->id() != 0);
framebuffer11->syncInternalState(context);
}
bool pointDrawMode = (drawMode == GL_POINTS);
if (pointDrawMode != mCurRasterState.pointDrawMode)
{
......
......@@ -30,40 +30,6 @@
namespace rx
{
namespace
{
void InvalidateRenderTarget(const gl::Context *context, RenderTarget11 *renderTarget)
{
if (renderTarget)
{
renderTarget->signalDirty(context);
}
}
RenderTarget11 *GetRenderTarget(std::unique_ptr<RenderTarget11> *pointer)
{
return pointer->get();
}
template <typename KeyT>
RenderTarget11 *GetRenderTarget(std::pair<KeyT, std::unique_ptr<RenderTarget11>> *pair)
{
return pair->second.get();
}
template <typename T>
void InvalidateRenderTargetContainer(const gl::Context *context, T *renderTargetContainer)
{
for (auto &rt : *renderTargetContainer)
{
InvalidateRenderTarget(context, GetRenderTarget(&rt));
}
}
} // anonymous namespace
TextureStorage11::SamplerKey::SamplerKey()
: baseLevel(0), mipLevels(0), swizzle(false), dropStencil(false)
{
......@@ -928,10 +894,6 @@ gl::Error TextureStorage11_2D::onDestroy(const gl::Context *context)
mRenderer->getStateManager()->invalidateBoundViews();
}
// Invalidate RenderTargets.
InvalidateRenderTargetContainer(context, &mRenderTarget);
InvalidateRenderTarget(context, mLevelZeroRenderTarget.get());
return gl::NoError();
}
......@@ -1024,18 +986,8 @@ gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(const gl::Context *
if (lastSetting != mUseLevelZeroTexture)
{
// Mark everything as dirty to be conservative.
if (mLevelZeroRenderTarget)
{
mLevelZeroRenderTarget->signalDirty(context);
}
for (auto &renderTarget : mRenderTarget)
{
if (renderTarget)
{
renderTarget->signalDirty(context);
}
}
ASSERT(mSubject);
mSubject->onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
}
return gl::NoError();
......@@ -1892,12 +1844,6 @@ gl::Error TextureStorage11_Cube::onDestroy(const gl::Context *context)
}
}
for (auto &faceRenderTargets : mRenderTarget)
{
InvalidateRenderTargetContainer(context, &faceRenderTargets);
}
InvalidateRenderTargetContainer(context, &mLevelZeroRenderTarget);
return gl::NoError();
}
......@@ -2542,9 +2488,6 @@ gl::Error TextureStorage11_3D::onDestroy(const gl::Context *context)
}
}
InvalidateRenderTargetContainer(context, &mLevelRenderTargets);
InvalidateRenderTargetContainer(context, &mLevelLayerRenderTargets);
return gl::NoError();
}
......@@ -2868,8 +2811,6 @@ gl::Error TextureStorage11_2DArray::onDestroy(const gl::Context *context)
}
mAssociatedImages.clear();
InvalidateRenderTargetContainer(context, &mRenderTargets);
return gl::NoError();
}
......@@ -3249,7 +3190,6 @@ TextureStorage11_2DMultisample::TextureStorage11_2DMultisample(Renderer11 *rende
gl::Error TextureStorage11_2DMultisample::onDestroy(const gl::Context *context)
{
InvalidateRenderTarget(context, mRenderTarget.get());
mRenderTarget.reset();
return gl::NoError();
}
......
......@@ -33,7 +33,7 @@ class Renderer11;
class RenderTarget11;
struct Renderer11DeviceCaps;
using RenderTargetArray = std::array<RenderTarget11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using RenderTargetArray11 = std::array<RenderTarget11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using RTVArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
namespace gl_d3d11
......
......@@ -24,11 +24,33 @@
namespace rx
{
namespace
{
void UpdateCachedRenderTarget(const gl::Context *context,
const gl::FramebufferAttachment *attachment,
RenderTarget9 *&cachedRenderTarget)
{
RenderTarget9 *newRenderTarget = nullptr;
if (attachment)
{
// TODO(jmadill): Don't swallow this error.
gl::Error error = attachment->getRenderTarget(context, &newRenderTarget);
if (error.isError())
{
ERR() << "Internal rendertarget error: " << error;
}
}
if (newRenderTarget != cachedRenderTarget)
{
cachedRenderTarget = newRenderTarget;
}
}
} // anonymous namespace
Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer)
: FramebufferD3D(data, renderer), mRenderer(renderer)
: FramebufferD3D(data, renderer), mRenderer(renderer), mCachedDepthStencilRenderTarget(nullptr)
{
ASSERT(mRenderer != nullptr);
mCachedColorRenderTargets.fill(nullptr);
}
Framebuffer9::~Framebuffer9()
......@@ -61,10 +83,8 @@ gl::Error Framebuffer9::invalidateSub(const gl::Context *context,
gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParameters &clearParams)
{
const gl::FramebufferAttachment *colorAttachment = mState.getColorAttachment(0);
const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment();
ANGLE_TRY(mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment));
ANGLE_TRY(mRenderer->applyRenderTarget(context, mCachedColorRenderTargets[0],
mCachedDepthStencilRenderTarget));
const gl::State &glState = context->getGLState();
float nearZ = glState.getNearPlane();
......@@ -74,7 +94,8 @@ gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParamet
mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
return mRenderer->clear(context, clearParams, colorAttachment, depthStencilAttachment);
return mRenderer->clear(context, clearParams, mCachedColorRenderTargets[0],
mCachedDepthStencilRenderTarget);
}
gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context,
......@@ -111,15 +132,17 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context,
HRESULT result;
IDirect3DSurface9 *systemSurface = nullptr;
bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
area.x == 0 && area.y == 0 &&
static_cast<UINT>(area.width) == desc.Width && static_cast<UINT>(area.height) == desc.Height &&
desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
bool directToPixels =
!pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() &&
area.x == 0 && area.y == 0 && static_cast<UINT>(area.width) == desc.Width &&
static_cast<UINT>(area.height) == desc.Height && desc.Format == D3DFMT_A8R8G8B8 &&
format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
if (directToPixels)
{
// Use the pixels ptr as a shared handle to write directly into client's memory
result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast<void**>(&pixels));
D3DPOOL_SYSTEMMEM, &systemSurface,
reinterpret_cast<void **>(&pixels));
if (FAILED(result))
{
// Try again without the shared handle
......@@ -408,4 +431,50 @@ gl::Error Framebuffer9::getSamplePosition(size_t index, GLfloat *xy) const
return gl::InternalError() << "getSamplePosition is unsupported to d3d9.";
}
void Framebuffer9::syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits)
{
FramebufferD3D::syncState(context, dirtyBits);
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
updateDepthStencilRenderTarget(context);
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
break;
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
break;
default:
{
ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 &&
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
size_t colorIndex =
static_cast<size_t>(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
updateColorRenderTarget(context, colorIndex);
break;
}
}
}
}
void Framebuffer9::updateColorRenderTarget(const gl::Context *context, size_t colorIndex)
{
UpdateCachedRenderTarget(context, mState.getColorAttachment(colorIndex),
mCachedColorRenderTargets[colorIndex]);
}
void Framebuffer9::updateDepthStencilRenderTarget(const gl::Context *context)
{
UpdateCachedRenderTarget(context, mState.getDepthOrStencilAttachment(),
mCachedDepthStencilRenderTarget);
}
} // namespace rx
......@@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
namespace rx
{
......@@ -32,6 +33,19 @@ class Framebuffer9 : public FramebufferD3D
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override;
const RenderTargetArray9 &getCachedColorRenderTargets() const
{
return mCachedColorRenderTargets;
}
const RenderTarget9 *getCachedDepthStencilRenderTarget() const
{
return mCachedDepthStencilRenderTarget;
}
private:
gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) override;
......@@ -55,9 +69,15 @@ class Framebuffer9 : public FramebufferD3D
GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override;
void updateColorRenderTarget(const gl::Context *context, size_t colorIndex);
void updateDepthStencilRenderTarget(const gl::Context *context);
Renderer9 *const mRenderer;
RenderTargetArray9 mCachedColorRenderTargets;
RenderTarget9 *mCachedDepthStencilRenderTarget;
};
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_
......@@ -121,10 +121,10 @@ Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManage
mMaxNullColorbufferLRU = 0;
for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
{
mNullColorbufferCache[i].lruCount = 0;
mNullColorbufferCache[i].width = 0;
mNullColorbufferCache[i].height = 0;
mNullColorbufferCache[i].buffer = nullptr;
mNullRenderTargetCache[i].lruCount = 0;
mNullRenderTargetCache[i].width = 0;
mNullRenderTargetCache[i].height = 0;
mNullRenderTargetCache[i].renderTarget = nullptr;
}
mAppliedVertexShader = nullptr;
......@@ -1043,7 +1043,10 @@ gl::Error Renderer9::updateState(const gl::Context *context, GLenum drawMode)
gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->cachedComplete());
ANGLE_TRY(applyRenderTarget(context, framebuffer));
Framebuffer9 *framebuffer9 = GetImplAs<Framebuffer9>(framebuffer);
ANGLE_TRY(applyRenderTarget(context, framebuffer9->getCachedColorRenderTargets()[0],
framebuffer9->getCachedDepthStencilRenderTarget()));
// Setting viewport state
setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode,
......@@ -1158,109 +1161,89 @@ bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSiz
return mPrimitiveCount > 0;
}
gl::Error Renderer9::getNullColorbuffer(const gl::Context *context,
const gl::FramebufferAttachment *depthbuffer,
const gl::FramebufferAttachment **outColorBuffer)
gl::Error Renderer9::getNullColorRenderTarget(const gl::Context *context,
const RenderTarget9 *depthRenderTarget,
const RenderTarget9 **outColorRenderTarget)
{
ASSERT(depthbuffer);
ASSERT(depthRenderTarget);
const gl::Extents &size = depthbuffer->getSize();
const gl::Extents &size = depthRenderTarget->getExtents();
// search cached nullcolorbuffers
for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
{
if (mNullColorbufferCache[i].buffer != nullptr &&
mNullColorbufferCache[i].width == size.width &&
mNullColorbufferCache[i].height == size.height)
if (mNullRenderTargetCache[i].renderTarget != nullptr &&
mNullRenderTargetCache[i].width == size.width &&
mNullRenderTargetCache[i].height == size.height)
{
mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU;
*outColorBuffer = mNullColorbufferCache[i].buffer;
mNullRenderTargetCache[i].lruCount = ++mMaxNullColorbufferLRU;
*outColorRenderTarget = mNullRenderTargetCache[i].renderTarget;
return gl::NoError();
}
}
auto *implFactory = context->getImplementation();
gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(implFactory, 0);
gl::Error error = nullRenderbuffer->setStorage(context, GL_NONE, size.width, size.height);
if (error.isError())
{
SafeDelete(nullRenderbuffer);
return error;
}
gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(
context, GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer);
RenderTargetD3D *nullRenderTarget = nullptr;
ANGLE_TRY(createRenderTarget(size.width, size.height, GL_NONE, 0, &nullRenderTarget));
// add nullbuffer to the cache
NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0];
NullRenderTargetCacheEntry *oldest = &mNullRenderTargetCache[0];
for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
{
if (mNullColorbufferCache[i].lruCount < oldest->lruCount)
if (mNullRenderTargetCache[i].lruCount < oldest->lruCount)
{
oldest = &mNullColorbufferCache[i];
oldest = &mNullRenderTargetCache[i];
}
}
delete oldest->buffer;
oldest->buffer = nullbuffer;
SafeDelete(oldest->renderTarget);
oldest->renderTarget = GetAs<RenderTarget9>(nullRenderTarget);
oldest->lruCount = ++mMaxNullColorbufferLRU;
oldest->width = size.width;
oldest->height = size.height;
*outColorBuffer = nullbuffer;
*outColorRenderTarget = oldest->renderTarget;
return gl::NoError();
}
gl::Error Renderer9::applyRenderTarget(const gl::Context *context,
const gl::FramebufferAttachment *colorAttachment,
const gl::FramebufferAttachment *depthStencilAttachment)
const RenderTarget9 *colorRenderTargetIn,
const RenderTarget9 *depthStencilRenderTarget)
{
const gl::FramebufferAttachment *renderAttachment = colorAttachment;
// if there is no color attachment we must synthesize a NULL colorattachment
// to keep the D3D runtime happy. This should only be possible if depth texturing.
if (renderAttachment == nullptr)
const RenderTarget9 *colorRenderTarget = colorRenderTargetIn;
if (colorRenderTarget == nullptr)
{
ANGLE_TRY(getNullColorbuffer(context, depthStencilAttachment, &renderAttachment));
ANGLE_TRY(getNullColorRenderTarget(context, depthStencilRenderTarget, &colorRenderTarget));
}
ASSERT(renderAttachment != nullptr);
ASSERT(colorRenderTarget != nullptr);
size_t renderTargetWidth = 0;
size_t renderTargetHeight = 0;
D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN;
RenderTarget9 *renderTarget = nullptr;
ANGLE_TRY(renderAttachment->getRenderTarget(context, &renderTarget));
ASSERT(renderTarget);
bool renderTargetChanged = false;
unsigned int renderTargetSerial = renderTarget->getSerial();
unsigned int renderTargetSerial = colorRenderTarget->getSerial();
if (renderTargetSerial != mAppliedRenderTargetSerial)
{
// Apply the render target on the device
IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface();
IDirect3DSurface9 *renderTargetSurface = colorRenderTarget->getSurface();
ASSERT(renderTargetSurface);
mDevice->SetRenderTarget(0, renderTargetSurface);
SafeRelease(renderTargetSurface);
renderTargetWidth = renderTarget->getWidth();
renderTargetHeight = renderTarget->getHeight();
renderTargetFormat = renderTarget->getD3DFormat();
renderTargetWidth = colorRenderTarget->getWidth();
renderTargetHeight = colorRenderTarget->getHeight();
renderTargetFormat = colorRenderTarget->getD3DFormat();
mAppliedRenderTargetSerial = renderTargetSerial;
renderTargetChanged = true;
}
RenderTarget9 *depthStencilRenderTarget = nullptr;
unsigned int depthStencilSerial = 0;
if (depthStencilAttachment != nullptr)
unsigned int depthStencilSerial = 0;
if (depthStencilRenderTarget != nullptr)
{
ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget));
ASSERT(depthStencilRenderTarget);
depthStencilSerial = depthStencilRenderTarget->getSerial();
}
......@@ -1278,8 +1261,11 @@ gl::Error Renderer9::applyRenderTarget(const gl::Context *context,
mDevice->SetDepthStencilSurface(depthStencilSurface);
SafeRelease(depthStencilSurface);
depthSize = depthStencilAttachment->getDepthSize();
stencilSize = depthStencilAttachment->getStencilSize();
const gl::InternalFormat &format =
gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat());
depthSize = format.depthBits;
stencilSize = format.stencilBits;
}
else
{
......@@ -1304,13 +1290,6 @@ gl::Error Renderer9::applyRenderTarget(const gl::Context *context,
return gl::NoError();
}
gl::Error Renderer9::applyRenderTarget(const gl::Context *context,
const gl::Framebuffer *framebuffer)
{
return applyRenderTarget(context, framebuffer->getColorbuffer(0),
framebuffer->getDepthOrStencilbuffer());
}
gl::Error Renderer9::applyVertexBuffer(const gl::Context *context,
GLenum mode,
GLint first,
......@@ -1927,8 +1906,8 @@ void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
gl::Error Renderer9::clear(const gl::Context *context,
const ClearParameters &clearParams,
const gl::FramebufferAttachment *colorBuffer,
const gl::FramebufferAttachment *depthStencilBuffer)
const RenderTarget9 *colorRenderTarget,
const RenderTarget9 *depthStencilRenderTarget)
{
if (clearParams.colorType != GL_FLOAT)
{
......@@ -1953,23 +1932,16 @@ gl::Error Renderer9::clear(const gl::Context *context,
DWORD stencil = clearParams.stencilValue & 0x000000FF;
unsigned int stencilUnmasked = 0x0;
if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0)
if (clearParams.clearStencil && depthStencilRenderTarget)
{
ASSERT(depthStencilBuffer != nullptr);
RenderTargetD3D *stencilRenderTarget = nullptr;
gl::Error error = depthStencilBuffer->getRenderTarget(context, &stencilRenderTarget);
if (error.isError())
const gl::InternalFormat &depthStencilFormat =
gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat());
if (depthStencilFormat.stencilBits > 0)
{
return error;
const d3d9::D3DFormat &d3dFormatInfo =
d3d9::GetD3DFormatInfo(depthStencilRenderTarget->getD3DFormat());
stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1;
}
RenderTarget9 *stencilRenderTarget9 = GetAs<RenderTarget9>(stencilRenderTarget);
ASSERT(stencilRenderTarget9);
const d3d9::D3DFormat &d3dFormatInfo =
d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat());
stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1;
}
const bool needMaskedStencilClear =
......@@ -1980,21 +1952,12 @@ gl::Error Renderer9::clear(const gl::Context *context,
D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0);
if (clearColor)
{
ASSERT(colorBuffer != nullptr);
ASSERT(colorRenderTarget != nullptr);
RenderTargetD3D *colorRenderTarget = nullptr;
gl::Error error = colorBuffer->getRenderTarget(context, &colorRenderTarget);
if (error.isError())
{
return error;
}
RenderTarget9 *colorRenderTarget9 = GetAs<RenderTarget9>(colorRenderTarget);
ASSERT(colorRenderTarget9);
const gl::InternalFormat &formatInfo = *colorBuffer->getFormat().info;
const gl::InternalFormat &formatInfo =
gl::GetSizedInternalFormatInfo(colorRenderTarget->getInternalFormat());
const d3d9::D3DFormat &d3dFormatInfo =
d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat());
d3d9::GetD3DFormatInfo(colorRenderTarget->getD3DFormat());
color =
D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0)
......@@ -2240,11 +2203,7 @@ void Renderer9::releaseDeviceResources()
for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
{
if (mNullColorbufferCache[i].buffer)
{
mNullColorbufferCache[i].buffer->detach(mDisplay->getProxyContext());
}
SafeDelete(mNullColorbufferCache[i].buffer);
SafeDelete(mNullRenderTargetCache[i].renderTarget);
}
}
......
......@@ -36,6 +36,7 @@ class Blit9;
class Context9;
class IndexDataManager;
class ProgramD3D;
class RenderTarget9;
class StreamingIndexBufferInterface;
class StaticIndexBufferInterface;
class VertexDataManager;
......@@ -139,10 +140,9 @@ class Renderer9 : public RendererD3D
GLenum frontFace,
bool ignoreViewport);
gl::Error applyRenderTarget(const gl::Context *context, const gl::Framebuffer *frameBuffer);
gl::Error applyRenderTarget(const gl::Context *context,
const gl::FramebufferAttachment *colorAttachment,
const gl::FramebufferAttachment *depthStencilAttachment);
const RenderTarget9 *colorRenderTarget,
const RenderTarget9 *depthStencilRenderTarget);
gl::Error applyUniforms(ProgramD3D *programD3D);
bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
gl::Error applyVertexBuffer(const gl::Context *context,
......@@ -160,8 +160,8 @@ class Renderer9 : public RendererD3D
gl::Error clear(const gl::Context *context,
const ClearParameters &clearParams,
const gl::FramebufferAttachment *colorBuffer,
const gl::FramebufferAttachment *depthStencilBuffer);
const RenderTarget9 *colorRenderTarget,
const RenderTarget9 *depthStencilRenderTarget);
void markAllStateDirty();
......@@ -436,9 +436,9 @@ class Renderer9 : public RendererD3D
gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB);
gl::Error getNullColorbuffer(const gl::Context *context,
const gl::FramebufferAttachment *depthbuffer,
const gl::FramebufferAttachment **outColorBuffer);
gl::Error getNullColorRenderTarget(const gl::Context *context,
const RenderTarget9 *depthRenderTarget,
const RenderTarget9 **outColorRenderTarget);
D3DPOOL getBufferPool(DWORD usage) const;
......@@ -523,13 +523,16 @@ class Renderer9 : public RendererD3D
{
NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12
};
struct NullColorbufferCacheEntry
struct NullRenderTargetCacheEntry
{
UINT lruCount;
int width;
int height;
gl::FramebufferAttachment *buffer;
} mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES];
RenderTarget9 *renderTarget;
};
std::array<NullRenderTargetCacheEntry, NUM_NULL_COLORBUFFER_CACHE_ENTRIES>
mNullRenderTargetCache;
UINT mMaxNullColorbufferLRU;
std::vector<TranslatedAttribute> mTranslatedAttribCache;
......
......@@ -24,6 +24,8 @@ namespace rx
{
class RenderTarget9;
using RenderTargetArray9 = std::array<RenderTarget9 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
namespace gl_d3d9
{
......
......@@ -28,6 +28,7 @@ using SubjectIndex = size_t;
enum class SubjectMessage
{
STATE_CHANGE,
DEPENDENT_DIRTY_BITS,
};
// The observing class inherits from this interface class.
......
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