D3D11: Enable dirty bits for Framebuffer11.

This patch works using a notification scheme - whenever a Texture or
Renderbuffer changes in such a way as to recreate its RenderTarget, we
pass a signal to the Framebuffer to invalidate some internal state.
Everything is entirely tracked in the Renderer11 layer, and the GL
layer is left untouched.

A RenderTarget11 now tracks points to which it is bound, and the
Framebuffer11 is mostly responsible for managing those links.

The three locations where we notify a Framebuffer when its bound
RenderTargets might be dirty are:

 1) RenderTarget11::~RenderTarget
 2) EGLImageD3D::copyToLocalRendertarget
 3) TextureStorage11_2D::useLevelZeroWorkaroundTexture

This patch gives about a 10% score increase in the D3D11 draw call
benchmark on my system.

BUG=angleproject:1260

Change-Id: Ide38aeadff4a2681bf5bd685e8ca3c9e2612a380
Reviewed-on: https://chromium-review.googlesource.com/327255
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill 2016-02-24 15:25:51 -05:00
Родитель d834e3dc0d
Коммит 1fbc59fe2e
19 изменённых файлов: 634 добавлений и 134 удалений

Просмотреть файл

@ -19,6 +19,7 @@ base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file_
# You might have to re-order these to find the specific version you want.
perftests_paths = [
os.path.join('out', 'Release_x64'),
os.path.join('out', 'Release'),
os.path.join('build', 'Release_x64'),
os.path.join('build', 'Release_Win32')

Просмотреть файл

@ -299,6 +299,11 @@ GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const
return mData.mDrawBufferStates[drawBuffer];
}
const std::vector<GLenum> &Framebuffer::getDrawBufferStates() const
{
return mData.getDrawBufferStates();
}
void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers)
{
auto &drawStates = mData.mDrawBufferStates;

Просмотреть файл

@ -119,6 +119,7 @@ class Framebuffer final : public LabeledObject
size_t getDrawbufferStateCount() const;
GLenum getDrawBufferState(size_t drawBuffer) const;
const std::vector<GLenum> &getDrawBufferStates() const;
void setDrawBuffers(size_t count, const GLenum *buffers);
const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const;
bool hasEnabledDrawBuffer() const;

Просмотреть файл

@ -123,6 +123,9 @@ gl::Error EGLImageD3D::copyToLocalRendertarget()
return error;
}
// This only currently applies do D3D11, where it invalidates FBOs with this Image attached.
curRenderTarget->signalDirty();
// Clear the source image buffers
mBuffer = nullptr;
mAttachmentBuffer = nullptr;

Просмотреть файл

@ -33,6 +33,9 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget
virtual unsigned int getSerial() const;
static unsigned int issueSerials(unsigned int count);
// Only currently applies to D3D11.
virtual void signalDirty() {}
private:
const unsigned int mSerial;
static unsigned int mCurrentSerial;

Просмотреть файл

@ -9,6 +9,7 @@
#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
#include "common/debug.h"
#include "common/BitSetIterator.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Clear11.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
@ -24,17 +25,9 @@
namespace rx
{
Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer)
: FramebufferD3D(data, renderer), mRenderer(renderer)
namespace
{
ASSERT(mRenderer != nullptr);
}
Framebuffer11::~Framebuffer11()
{
}
static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment)
gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment)
{
if (attachment && attachment->type() == GL_TEXTURE)
{
@ -61,6 +54,67 @@ static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *a
return gl::Error(GL_NO_ERROR);
}
void UpdateCachedRenderTarget(const gl::FramebufferAttachment *attachment,
RenderTarget11 *&cachedRenderTarget,
const NotificationCallback &callbackFunc)
{
RenderTarget11 *newRenderTarget = nullptr;
if (attachment)
{
attachment->getRenderTarget(&newRenderTarget);
}
if (newRenderTarget != cachedRenderTarget)
{
if (cachedRenderTarget)
{
cachedRenderTarget->removeDirtyCallback(&callbackFunc);
}
if (newRenderTarget)
{
newRenderTarget->addDirtyCallback(&callbackFunc);
}
cachedRenderTarget = newRenderTarget;
}
}
} // anonymous namespace
Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer)
: FramebufferD3D(data, renderer), mRenderer(renderer), mCachedDepthStencilRenderTarget(nullptr)
{
ASSERT(mRenderer != nullptr);
mCachedColorRenderTargets.fill(nullptr);
for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex)
{
auto callback = [this, colorIndex]()
{
this->markColorRenderTargetDirty(colorIndex);
};
mColorRenderTargetsDirty.push_back(callback);
}
mDepthStencilRenderTargetDirty = [this]()
{
this->markDepthStencilRenderTargetDirty();
};
}
Framebuffer11::~Framebuffer11()
{
for (size_t colorIndex = 0; colorIndex < mCachedColorRenderTargets.size(); ++colorIndex)
{
auto *colorRenderTarget = mCachedColorRenderTargets[colorIndex];
if (colorRenderTarget)
{
colorRenderTarget->removeDirtyCallback(&mColorRenderTargetsDirty[colorIndex]);
}
}
if (mCachedDepthStencilRenderTarget)
{
mCachedDepthStencilRenderTarget->removeDirtyCallback(&mDepthStencilRenderTargetDirty);
}
}
gl::Error Framebuffer11::invalidateSwizzles() const
{
for (const auto &colorAttachment : mData.getColorAttachments())
@ -425,4 +479,77 @@ GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *rende
return dxgiFormatInfo.internalFormat;
}
void Framebuffer11::updateColorRenderTarget(size_t colorIndex)
{
UpdateCachedRenderTarget(mData.getColorAttachment(colorIndex),
mCachedColorRenderTargets[colorIndex],
mColorRenderTargetsDirty[colorIndex]);
}
void Framebuffer11::updateDepthStencilRenderTarget()
{
UpdateCachedRenderTarget(mData.getDepthOrStencilAttachment(), mCachedDepthStencilRenderTarget,
mDepthStencilRenderTargetDirty);
}
void Framebuffer11::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
{
mRenderer->getStateManager()->invalidateRenderTarget();
const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits;
mInternalDirtyBits.reset();
for (auto dirtyBit : angle::IterateBitSet(mergedDirtyBits))
{
switch (dirtyBit)
{
case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
updateDepthStencilRenderTarget();
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
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(colorIndex);
break;
}
}
}
// We should not have dirtied any additional state during our sync.
ASSERT(!mInternalDirtyBits.any());
FramebufferD3D::syncState(dirtyBits);
}
void Framebuffer11::markColorRenderTargetDirty(size_t colorIndex)
{
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
mCachedColorRenderTargets[colorIndex] = nullptr;
}
void Framebuffer11::markDepthStencilRenderTargetDirty()
{
// Stencil is redundant in this case.
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
mCachedDepthStencilRenderTarget = nullptr;
}
bool Framebuffer11::hasAnyInternalDirtyBit() const
{
return mInternalDirtyBits.any();
}
void Framebuffer11::syncInternalState() const
{
// TODO(jmadill): Clean up this hack.
const_cast<Framebuffer11 *>(this)->syncState(gl::Framebuffer::DirtyBits());
}
} // namespace rx

Просмотреть файл

@ -10,6 +10,7 @@
#define LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@ -28,6 +29,24 @@ class Framebuffer11 : public FramebufferD3D
// Invalidate the cached swizzles of all bound texture attachments.
gl::Error invalidateSwizzles() const;
void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override;
const RenderTargetArray &getCachedColorRenderTargets() const
{
return mCachedColorRenderTargets;
}
const RenderTarget11 *getCachedDepthStencilRenderTarget() const
{
return mCachedDepthStencilRenderTarget;
}
void markColorRenderTargetDirty(size_t colorIndex);
void markDepthStencilRenderTargetDirty();
bool hasAnyInternalDirtyBit() const;
// TODO(jmadill): make this non-const
void syncInternalState() const;
private:
gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override;
@ -46,7 +65,17 @@ class Framebuffer11 : public FramebufferD3D
GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override;
void updateColorRenderTarget(size_t colorIndex);
void updateDepthStencilRenderTarget();
Renderer11 *const mRenderer;
RenderTargetArray mCachedColorRenderTargets;
RenderTarget11 *mCachedDepthStencilRenderTarget;
std::vector<NotificationCallback> mColorRenderTargetsDirty;
NotificationCallback mDepthStencilRenderTargetDirty;
gl::Framebuffer::DirtyBits mInternalDirtyBits;
};
}

Просмотреть файл

@ -178,6 +178,39 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth
return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
}
RenderTarget11::RenderTarget11()
{
}
RenderTarget11::~RenderTarget11()
{
signalDirty();
}
void RenderTarget11::addDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.insert(callback);
}
void RenderTarget11::removeDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.erase(callback);
}
void RenderTarget11::signalDirty()
{
if (mDirtyCallbacks.empty())
return;
for (const auto &callback : mDirtyCallbacks)
{
(*callback)();
}
// Clear the signal list. We can't do this in the callback because it mutates the iterator.
mDirtyCallbacks.clear();
}
TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv,
GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples)
: mWidth(width),

Просмотреть файл

@ -12,6 +12,8 @@
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
class SwapChain11;
@ -20,8 +22,8 @@ class Renderer11;
class RenderTarget11 : public RenderTargetD3D
{
public:
RenderTarget11() { }
virtual ~RenderTarget11() { }
RenderTarget11();
virtual ~RenderTarget11();
virtual ID3D11Resource *getTexture() const = 0;
virtual ID3D11RenderTargetView *getRenderTargetView() const = 0;
@ -31,6 +33,13 @@ class RenderTarget11 : public RenderTargetD3D
virtual unsigned int getSubresourceIndex() const = 0;
virtual DXGI_FORMAT getDXGIFormat() const = 0;
void addDirtyCallback(const NotificationCallback *callback);
void removeDirtyCallback(const NotificationCallback *callback);
void signalDirty() override;
protected:
std::set<const NotificationCallback *> mDirtyCallbacks;
};
class TextureRenderTarget11 : public RenderTarget11

Просмотреть файл

@ -150,9 +150,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurNear(0.0f),
mCurFar(0.0f),
mViewportBounds(),
mCurPresentPathFastEnabled(false),
mCurPresentPathFastColorBufferHeight(0),
mAppliedDSV(angle::DirtyPointer)
mRenderTargetIsDirty(false)
{
mCurBlendState.blend = false;
mCurBlendState.sourceBlendRGB = GL_ONE;
@ -459,6 +457,9 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
mViewportStateIsDirty = true;
}
break;
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
mRenderTargetIsDirty = true;
break;
default:
break;
}
@ -773,11 +774,7 @@ void StateManager11::setViewport(const gl::Caps *caps,
void StateManager11::invalidateRenderTarget()
{
for (auto &appliedRTV : mAppliedRTVs)
{
appliedRTV = angle::DirtyPointer;
}
mAppliedDSV = angle::DirtyPointer;
mRenderTargetIsDirty = true;
}
void StateManager11::invalidateBoundViews()
@ -802,34 +799,6 @@ void StateManager11::invalidateEverything()
invalidateBoundViews();
}
bool StateManager11::setRenderTargets(const RenderTargetArray &renderTargets,
ID3D11DepthStencilView *depthStencil)
{
// TODO(jmadill): Use context caps?
UINT drawBuffers = mRenderer->getRendererCaps().maxDrawBuffers;
// Apply the render target and depth stencil
size_t arraySize = sizeof(uintptr_t) * drawBuffers;
if (memcmp(renderTargets.data(), mAppliedRTVs.data(), arraySize) == 0 &&
reinterpret_cast<uintptr_t>(depthStencil) == mAppliedDSV)
{
return false;
}
// The D3D11 blend state is heavily dependent on the current render target.
mBlendStateIsDirty = true;
for (UINT rtIndex = 0; rtIndex < drawBuffers; rtIndex++)
{
mAppliedRTVs[rtIndex] = reinterpret_cast<uintptr_t>(renderTargets[rtIndex]);
}
mAppliedDSV = reinterpret_cast<uintptr_t>(depthStencil);
mRenderer->getDeviceContext()->OMSetRenderTargets(drawBuffers, renderTargets.data(),
depthStencil);
return true;
}
void StateManager11::setRenderTarget(ID3D11RenderTargetView *renderTarget,
ID3D11DepthStencilView *depthStencil)
{
@ -954,6 +923,22 @@ void StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType,
}
}
void StateManager11::unsetConflictingAttachmentResources(
const gl::FramebufferAttachment *attachment,
ID3D11Resource *resource)
{
// Unbind render target SRVs from the shader here to prevent D3D11 warnings.
if (attachment->type() == GL_TEXTURE)
{
uintptr_t resourcePtr = reinterpret_cast<uintptr_t>(resource);
const gl::ImageIndex &index = attachment->getTextureImageIndex();
// The index doesn't need to be corrected for the small compressed texture workaround
// because a rendertarget is never compressed.
unsetConflictingSRVs(gl::SAMPLER_VERTEX, resourcePtr, index);
unsetConflictingSRVs(gl::SAMPLER_PIXEL, resourcePtr, index);
}
}
void StateManager11::initialize(const gl::Caps &caps)
{
mCurVertexSRVs.initialize(caps.maxVertexTextureImageUnits);
@ -965,85 +950,90 @@ void StateManager11::initialize(const gl::Caps &caps)
gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
{
const Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
gl::Error error = framebuffer11->invalidateSwizzles();
if (error.isError())
{
return error;
}
if (framebuffer11->hasAnyInternalDirtyBit())
{
ASSERT(framebuffer->id() != 0);
framebuffer11->syncInternalState();
}
if (!mRenderTargetIsDirty)
{
return gl::Error(GL_NO_ERROR);
}
mRenderTargetIsDirty = false;
// Check for zero-sized default framebuffer, which is a special case.
// in this case we do not wish to modify any state and just silently return false.
// 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)
{
return gl::Error(GL_NO_ERROR);
}
}
// Get the color render buffer and serial
// Also extract the render target dimensions and view
unsigned int renderTargetWidth = 0;
unsigned int renderTargetHeight = 0;
DXGI_FORMAT renderTargetFormat = DXGI_FORMAT_UNKNOWN;
RenderTargetArray framebufferRTVs;
RTVArray framebufferRTVs;
bool missingColorRenderTarget = true;
framebufferRTVs.fill(nullptr);
const Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender();
const auto &colorRTs = framebuffer11->getCachedColorRenderTargets();
for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
size_t appliedRTIndex = 0;
bool skipInactiveRTs = mRenderer->getWorkarounds().mrtPerfWorkaround;
const auto &drawStates = framebuffer->getDrawBufferStates();
for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex)
{
const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
const RenderTarget11 *renderTarget = colorRTs[rtIndex];
if (colorbuffer)
// Skip inactive rendertargets if the workaround is enabled.
if (skipInactiveRTs && (!renderTarget || drawStates[rtIndex] == GL_NONE))
{
// the draw buffer must be either "none", "back" for the default buffer or the same
// index as this color (in order)
continue;
}
// check for zero-sized default framebuffer, which is a special case.
// in this case we do not wish to modify any state and just silently return false.
// this will not report any gl error but will cause the calling method to return.
const gl::Extents &size = colorbuffer->getSize();
if (size.width == 0 || size.height == 0)
{
return gl::Error(GL_NO_ERROR);
}
// Extract the render target dimensions and view
RenderTarget11 *renderTarget = NULL;
gl::Error error = colorbuffer->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
ASSERT(renderTarget);
framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView();
ASSERT(framebufferRTVs[colorAttachment]);
if (renderTarget)
{
framebufferRTVs[appliedRTIndex] = renderTarget->getRenderTargetView();
ASSERT(framebufferRTVs[appliedRTIndex]);
if (missingColorRenderTarget)
{
renderTargetWidth = renderTarget->getWidth();
renderTargetHeight = renderTarget->getHeight();
renderTargetFormat = renderTarget->getDXGIFormat();
missingColorRenderTarget = false;
}
// Unbind render target SRVs from the shader here to prevent D3D11 warnings.
if (colorbuffer->type() == GL_TEXTURE)
{
uintptr_t rtResource =
reinterpret_cast<uintptr_t>(GetViewResource(framebufferRTVs[colorAttachment]));
const gl::ImageIndex &index = colorbuffer->getTextureImageIndex();
// The index doesn't need to be corrected for the small compressed texture
// workaround
// because a rendertarget is never compressed.
unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index);
unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index);
}
}
// Unset conflicting texture SRVs
const auto *attachment = framebuffer->getColorbuffer(rtIndex);
ASSERT(attachment);
unsetConflictingAttachmentResources(attachment, renderTarget->getTexture());
appliedRTIndex++;
}
// Get the depth stencil buffers
ID3D11DepthStencilView *framebufferDSV = NULL;
const gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer();
if (depthStencil)
ID3D11DepthStencilView *framebufferDSV = nullptr;
const auto *depthStencilRenderTarget = framebuffer11->getCachedDepthStencilRenderTarget();
if (depthStencilRenderTarget)
{
RenderTarget11 *depthStencilRenderTarget = NULL;
gl::Error error = depthStencil->getRenderTarget(&depthStencilRenderTarget);
if (error.isError())
{
return error;
}
ASSERT(depthStencilRenderTarget);
framebufferDSV = depthStencilRenderTarget->getDepthStencilView();
ASSERT(framebufferDSV);
@ -1055,29 +1045,23 @@ gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer)
renderTargetHeight = depthStencilRenderTarget->getHeight();
}
// Unbind render target SRVs from the shader here to prevent D3D11 warnings.
if (depthStencil->type() == GL_TEXTURE)
{
uintptr_t depthStencilResource =
reinterpret_cast<uintptr_t>(GetViewResource(framebufferDSV));
const gl::ImageIndex &index = depthStencil->getTextureImageIndex();
// The index doesn't need to be corrected for the small compressed texture workaround
// because a rendertarget is never compressed.
unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index);
unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index);
}
// Unset conflicting texture SRVs
const auto *attachment = framebuffer->getDepthOrStencilbuffer();
ASSERT(attachment);
unsetConflictingAttachmentResources(attachment, depthStencilRenderTarget->getTexture());
}
if (setRenderTargets(framebufferRTVs, framebufferDSV))
{
setViewportBounds(renderTargetWidth, renderTargetHeight);
}
// TODO(jmadill): Use context caps?
UINT drawBuffers = mRenderer->getRendererCaps().maxDrawBuffers;
gl::Error error = framebuffer11->invalidateSwizzles();
if (error.isError())
{
return error;
}
// Apply the render target and depth stencil
mRenderer->getDeviceContext()->OMSetRenderTargets(drawBuffers, framebufferRTVs.data(),
framebufferDSV);
// The D3D11 blend state is heavily dependent on the current render target.
mBlendStateIsDirty = true;
setViewportBounds(renderTargetWidth, renderTargetHeight);
return gl::Error(GL_NO_ERROR);
}

Просмотреть файл

@ -81,8 +81,6 @@ class StateManager11 final : angle::NonCopyable
void invalidateRenderTarget();
void invalidateBoundViews();
void invalidateEverything();
bool setRenderTargets(const RenderTargetArray &renderTargets,
ID3D11DepthStencilView *depthStencil);
void setRenderTarget(ID3D11RenderTargetView *renderTarget,
ID3D11DepthStencilView *depthStencil);
@ -91,10 +89,12 @@ class StateManager11 final : angle::NonCopyable
gl::Error onMakeCurrent(const gl::Data &data);
private:
void setViewportBounds(const int width, const int height);
void unsetConflictingSRVs(gl::SamplerType shaderType,
uintptr_t resource,
const gl::ImageIndex &index);
void setViewportBounds(const int width, const int height);
void unsetConflictingAttachmentResources(const gl::FramebufferAttachment *attachment,
ID3D11Resource *resource);
Renderer11 *mRenderer;
@ -142,8 +142,7 @@ class StateManager11 final : angle::NonCopyable
int mCurPresentPathFastColorBufferHeight;
// Current RenderTarget state
std::array<uintptr_t, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> mAppliedRTVs;
uintptr_t mAppliedDSV;
bool mRenderTargetIsDirty;
// Queries that are currently active in this state
std::set<Query11 *> mCurrentQueries;

Просмотреть файл

@ -960,6 +960,8 @@ gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage)
gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture)
{
bool lastSetting = mUseLevelZeroTexture;
if (useLevelZeroTexture && mMipLevels > 1)
{
if (!mUseLevelZeroTexture && mTexture)
@ -997,6 +999,22 @@ gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTe
mUseLevelZeroTexture = false;
}
if (lastSetting != mUseLevelZeroTexture)
{
// Mark everything as dirty to be conservative.
if (mLevelZeroRenderTarget)
{
mLevelZeroRenderTarget->signalDirty();
}
for (auto *renderTarget : mRenderTarget)
{
if (renderTarget)
{
renderTarget->signalDirty();
}
}
}
return gl::Error(GL_NO_ERROR);
}

Просмотреть файл

@ -11,6 +11,7 @@
#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
#include <array>
#include <functional>
#include <vector>
#include "libANGLE/angletypes.h"
@ -30,7 +31,8 @@ class RenderTarget11;
struct WorkaroundsD3D;
struct Renderer11DeviceCaps;
using RenderTargetArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using RenderTargetArray = std::array<RenderTarget11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using RTVArray = std::array<ID3D11RenderTargetView *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>;
namespace gl_d3d11
{
@ -395,6 +397,8 @@ gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
using NotificationCallback = std::function<void()>;
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_

Просмотреть файл

@ -30,8 +30,8 @@
'<(angle_path)/src/tests/gl_tests/DrawElementsTest.cpp',
'<(angle_path)/src/tests/gl_tests/ETCTextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/FenceSyncTests.cpp',
'<(angle_path)/src/tests/gl_tests/FramebufferFormatsTest.cpp',
'<(angle_path)/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp',
'<(angle_path)/src/tests/gl_tests/FramebufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/GLSLTest.cpp',
'<(angle_path)/src/tests/gl_tests/ImageTest.cpp',
'<(angle_path)/src/tests/gl_tests/IncompleteTextureTest.cpp',

Просмотреть файл

@ -3,6 +3,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Framebuffer tests:
// Various tests related for Frambuffers.
//
#include "test_utils/ANGLETest.h"
@ -38,8 +41,13 @@ class FramebufferFormatsTest : public ANGLETest
}
}
void testBitCounts(GLuint fbo, GLint minRedBits, GLint minGreenBits, GLint minBlueBits,
GLint minAlphaBits, GLint minDepthBits, GLint minStencilBits)
void testBitCounts(GLuint fbo,
GLint minRedBits,
GLint minGreenBits,
GLint minBlueBits,
GLint minAlphaBits,
GLint minDepthBits,
GLint minStencilBits)
{
checkBitCount(fbo, GL_RED_BITS, minRedBits);
checkBitCount(fbo, GL_GREEN_BITS, minGreenBits);
@ -49,7 +57,10 @@ class FramebufferFormatsTest : public ANGLETest
checkBitCount(fbo, GL_STENCIL_BITS, minStencilBits);
}
void testTextureFormat(GLenum internalFormat, GLint minRedBits, GLint minGreenBits, GLint minBlueBits,
void testTextureFormat(GLenum internalFormat,
GLint minRedBits,
GLint minGreenBits,
GLint minBlueBits,
GLint minAlphaBits)
{
glGenTextures(1, &mTexture);
@ -61,7 +72,9 @@ class FramebufferFormatsTest : public ANGLETest
testBitCounts(mFramebuffer, minRedBits, minGreenBits, minBlueBits, minAlphaBits, 0, 0);
}
void testRenderbufferMultisampleFormat(int minESVersion, GLenum attachmentType, GLenum internalFormat)
void testRenderbufferMultisampleFormat(int minESVersion,
GLenum attachmentType,
GLenum internalFormat)
{
// TODO(geofflang): Figure out why this is broken on Intel OpenGL
if (isIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
@ -290,7 +303,8 @@ TEST_P(FramebufferFormatsTest, IncompleteCubeMap)
ASSERT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(FramebufferFormatsTest,
ES2_D3D9(),
ES2_D3D11(),
@ -299,3 +313,45 @@ ANGLE_INSTANTIATE_TEST(FramebufferFormatsTest,
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES());
class FramebufferInvalidateTest : public ANGLETest
{
protected:
FramebufferInvalidateTest() : mFramebuffer(0), mRenderbuffer(0) {}
void SetUp() override
{
ANGLETest::SetUp();
glGenFramebuffers(1, &mFramebuffer);
glGenRenderbuffers(1, &mRenderbuffer);
}
void TearDown() override
{
glDeleteFramebuffers(1, &mFramebuffer);
glDeleteRenderbuffers(1, &mRenderbuffer);
ANGLETest::TearDown();
}
GLuint mFramebuffer;
GLuint mRenderbuffer;
};
// Covers invalidating an incomplete framebuffer. This should be a no-op, but should not error.
TEST_P(FramebufferInvalidateTest, Incomplete)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
glCheckFramebufferStatus(GL_FRAMEBUFFER));
std::vector<GLenum> attachments;
attachments.push_back(GL_COLOR_ATTACHMENT0);
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data());
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(FramebufferInvalidateTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());

Просмотреть файл

@ -1252,6 +1252,75 @@ TEST_P(ImageTest, Respecification)
glDeleteTextures(1, &target);
}
// First render to a target texture, then respecify the source texture, orphaning it.
// The target texture's FBO should be notified of the target texture's orphaning.
TEST_P(ImageTest, RespecificationWithFBO)
{
EGLWindow *window = getEGLWindow();
if (!extensionEnabled("OES_EGL_image") ||
!eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") ||
!eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_2D_image"))
{
std::cout << "Test skipped because OES_EGL_image, EGL_KHR_image_base or "
"EGL_KHR_gl_texture_2D_image is not available."
<< std::endl;
return;
}
// Simple shader
const std::string &vertexSource =
"attribute vec2 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
"}";
const std::string &fragmentSource =
"void main()\n"
"{\n"
" gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
"}";
GLuint program = CompileProgram(vertexSource, fragmentSource);
ASSERT_NE(0u, program);
GLubyte originalData[4] = {255, 0, 255, 255};
GLubyte updateData[4] = {0, 255, 0, 255};
// Create the Image
GLuint source;
EGLImageKHR image;
createEGLImage2DTextureSource(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, originalData, &source, &image);
// Create the target
GLuint target;
createEGLImageTargetTexture2D(image, &target);
// Render to the target texture
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target, 0);
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
// Respecify source with same parameters. This should not change the texture storage in D3D11.
glBindTexture(GL_TEXTURE_2D, source);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, updateData);
// Expect that the source texture has the updated data
verifyResults2D(source, updateData);
// Render to the target texture again and verify it gets the rendered pixels.
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
// Clean up
glDeleteTextures(1, &source);
eglDestroyImageKHR(window->getDisplay(), image);
glDeleteTextures(1, &target);
glDeleteProgram(program);
glDeleteFramebuffers(1, &fbo);
}
// Test that respecifying a level of the target texture orphans it and keeps a copy of the EGLimage
// data
TEST_P(ImageTest, RespecificationOfOtherLevel)

Просмотреть файл

@ -240,5 +240,148 @@ TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync)
ASSERT_GL_NO_ERROR();
}
class StateChangeRenderTest : public StateChangeTest
{
protected:
StateChangeRenderTest() : mProgram(0), mRenderbuffer(0) {}
void SetUp() override
{
StateChangeTest::SetUp();
const std::string vertexShaderSource =
"attribute vec2 position;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
"}";
const std::string fragmentShaderSource =
"uniform highp vec4 uniformColor;\n"
"void main() {\n"
" gl_FragColor = uniformColor;\n"
"}";
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(0u, mProgram);
glGenRenderbuffers(1, &mRenderbuffer);
}
void TearDown() override
{
glDeleteProgram(mProgram);
glDeleteRenderbuffers(1, &mRenderbuffer);
StateChangeTest::TearDown();
}
void setUniformColor(const GLColor &color)
{
glUseProgram(mProgram);
const Vector4 &normalizedColor = color.toNormalizedVector();
GLint uniformLocation = glGetUniformLocation(mProgram, "uniformColor");
ASSERT_NE(-1, uniformLocation);
glUniform4fv(uniformLocation, 1, normalizedColor.data());
}
GLuint mProgram;
GLuint mRenderbuffer;
};
// Test that re-creating a currently attached texture works as expected.
TEST_P(StateChangeRenderTest, RecreateTexture)
{
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);
// Draw with red to the FBO.
GLColor red(255, 0, 0, 255);
setUniformColor(red);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, red);
// Recreate the texture with green.
GLColor green(0, 255, 0, 255);
std::vector<GLColor> greenPixels(32 * 32, green);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE,
greenPixels.data());
EXPECT_PIXEL_COLOR_EQ(0, 0, green);
// Verify drawing blue gives blue. This covers the FBO sync with D3D dirty bits.
GLColor blue(0, 0, 255, 255);
setUniformColor(blue);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
EXPECT_GL_NO_ERROR();
}
// Test that re-creating a currently attached renderbuffer works as expected.
TEST_P(StateChangeRenderTest, RecreateRenderbuffer)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
// Draw with red to the FBO.
GLColor red(255, 0, 0, 255);
setUniformColor(red);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, red);
// Recreate the renderbuffer and clear to green.
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 32, 32);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLColor green(0, 255, 0, 255);
EXPECT_PIXEL_COLOR_EQ(0, 0, green);
// Verify drawing blue gives blue. This covers the FBO sync with D3D dirty bits.
GLColor blue(0, 0, 255, 255);
setUniformColor(blue);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
EXPECT_GL_NO_ERROR();
}
// Test that recreating a texture with GenerateMipmaps signals the FBO is dirty.
TEST_P(StateChangeRenderTest, GenerateMipmap)
{
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);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
// Draw once to set the RenderTarget in D3D11
GLColor red(255, 0, 0, 255);
setUniformColor(red);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, red);
// This will trigger the texture to be re-created on FL9_3.
glGenerateMipmap(GL_TEXTURE_2D);
// Now ensure we don't have a stale render target.
GLColor blue(0, 0, 255, 255);
setUniformColor(blue);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
ANGLE_INSTANTIATE_TEST(StateChangeRenderTest,
ES2_D3D9(),
ES2_D3D11(),
ES2_OPENGL(),
ES2_D3D11_FL9_3());
ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL());

Просмотреть файл

@ -15,6 +15,14 @@
namespace angle
{
namespace
{
float ColorNorm(GLubyte channelValue)
{
return static_cast<float>(channelValue) / 255.0f;
}
} // anonymous namespace
GLColor::GLColor() : R(0), G(0), B(0), A(0)
{
}
@ -28,6 +36,11 @@ GLColor::GLColor(GLuint colorValue) : R(0), G(0), B(0), A(0)
memcpy(&R, &colorValue, sizeof(GLuint));
}
Vector4 GLColor::toNormalizedVector() const
{
return Vector4(ColorNorm(R), ColorNorm(G), ColorNorm(B), ColorNorm(A));
}
GLColor ReadColor(GLint x, GLint y)
{
GLColor actual;

Просмотреть файл

@ -17,6 +17,7 @@
#include "angle_test_configs.h"
#include "common/angleutils.h"
#include "shader_utils.h"
#include "Vector.h"
#define EXPECT_GL_ERROR(err) EXPECT_EQ(static_cast<GLenum>(err), glGetError())
#define EXPECT_GL_NO_ERROR() EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError())
@ -47,6 +48,8 @@ struct GLColor
GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a);
GLColor(GLuint colorValue);
Vector4 toNormalizedVector() const;
GLubyte R, G, B, A;
};