Commit 88e03221 by Stephen Martinis Committed by Commit Bot

Unset conflicting SRVs and UAVs

D3D11 cannot allow the same (sub)-resource bound as both a SRV and an UAV at the same time. Unset conflicting SRVs and UVAs between render pipeline and compute pipeline. Bug: angleproject:3152 TEST=angle_end2end_tests.ComputeShaderTest.* Change-Id: I9cb8b902edbf987166a57af314af6b21a6874998 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1576504Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Xinghua Cao <xinghua.cao@intel.com>
parent 6c824a1b
......@@ -893,6 +893,22 @@ unsigned int ElementTypeSize(GLenum elementType)
}
}
PipelineType GetPipelineType(ShaderType type)
{
switch (type)
{
case ShaderType::Vertex:
case ShaderType::Fragment:
case ShaderType::Geometry:
return PipelineType::GraphicsPipeline;
case ShaderType::Compute:
return PipelineType::ComputePipeline;
default:
UNREACHABLE();
return PipelineType::GraphicsPipeline;
}
}
} // namespace gl
namespace egl
......
......@@ -202,6 +202,14 @@ T GetClampedVertexCount(size_t vertexCount)
static constexpr size_t kMax = static_cast<size_t>(std::numeric_limits<T>::max());
return static_cast<T>(vertexCount > kMax ? kMax : vertexCount);
}
enum class PipelineType
{
GraphicsPipeline = 0,
ComputePipeline = 1,
};
PipelineType GetPipelineType(ShaderType shaderType);
} // namespace gl
namespace egl
......
......@@ -101,6 +101,47 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR
return false;
}
bool ImageIndexConflictsWithUAV(const gl::ImageIndex &index, D3D11_UNORDERED_ACCESS_VIEW_DESC desc)
{
unsigned mipLevel = index.getLevelIndex();
gl::TextureType textureType = index.getType();
switch (desc.ViewDimension)
{
case D3D11_UAV_DIMENSION_TEXTURE2D:
{
return textureType == gl::TextureType::_2D && mipLevel == desc.Texture2D.MipSlice;
}
case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
{
GLint layerIndex = index.getLayerIndex();
unsigned mipSlice = desc.Texture2DArray.MipSlice;
unsigned firstArraySlice = desc.Texture2DArray.FirstArraySlice;
unsigned lastArraySlice = firstArraySlice + desc.Texture2DArray.ArraySize;
return (textureType == gl::TextureType::_2DArray ||
textureType == gl::TextureType::CubeMap) &&
(mipLevel == mipSlice && gl::RangeUI(firstArraySlice, lastArraySlice)
.contains(static_cast<UINT>(layerIndex)));
}
case D3D11_UAV_DIMENSION_TEXTURE3D:
{
GLint layerIndex = index.getLayerIndex();
unsigned mipSlice = desc.Texture3D.MipSlice;
unsigned firstWSlice = desc.Texture3D.FirstWSlice;
unsigned lastWSlice = firstWSlice + desc.Texture3D.WSize;
return textureType == gl::TextureType::_3D &&
(mipLevel == mipSlice &&
gl::RangeUI(firstWSlice, lastWSlice).contains(static_cast<UINT>(layerIndex)));
}
default:
return false;
}
}
// Does *not* increment the resource ref count!!
ID3D11Resource *GetViewResource(ID3D11View *view)
{
......@@ -690,9 +731,14 @@ StateManager11::StateManager11(Renderer11 *renderer)
mCurRasterState.pointDrawMode = false;
mCurRasterState.multiSample = false;
// Start with all internal dirty bits set.
// Start with all internal dirty bits set except DIRTY_BIT_COMPUTE_SRVUAV_STATE and
// DIRTY_BIT_GRAPHICS_SRVUAV_STATE.
mInternalDirtyBits.set();
mInternalDirtyBits.reset(DIRTY_BIT_GRAPHICS_SRVUAV_STATE);
mInternalDirtyBits.reset(DIRTY_BIT_COMPUTE_SRVUAV_STATE);
mGraphicsDirtyBitsMask.set();
mGraphicsDirtyBitsMask.reset(DIRTY_BIT_COMPUTE_SRVUAV_STATE);
mComputeDirtyBitsMask.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
mComputeDirtyBitsMask.set(DIRTY_BIT_PROGRAM_UNIFORMS);
mComputeDirtyBitsMask.set(DIRTY_BIT_DRIVER_UNIFORMS);
......@@ -700,6 +746,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mComputeDirtyBitsMask.set(DIRTY_BIT_PROGRAM_ATOMIC_COUNTER_BUFFERS);
mComputeDirtyBitsMask.set(DIRTY_BIT_PROGRAM_SHADER_STORAGE_BUFFERS);
mComputeDirtyBitsMask.set(DIRTY_BIT_SHADERS);
mComputeDirtyBitsMask.set(DIRTY_BIT_COMPUTE_SRVUAV_STATE);
// Initially all current value attributes must be updated on first use.
mDirtyCurrentValueAttribs.set();
......@@ -727,9 +774,21 @@ void StateManager11::setShaderResourceInternal(gl::ShaderType shaderType,
switch (shaderType)
{
case gl::ShaderType::Vertex:
if (srvPtr)
{
uintptr_t resource = reinterpret_cast<uintptr_t>(GetViewResource(srvPtr));
unsetConflictingUAVs(gl::PipelineType::GraphicsPipeline,
gl::ShaderType::Compute, resource, nullptr);
}
deviceContext->VSSetShaderResources(resourceSlot, 1, &srvPtr);
break;
case gl::ShaderType::Fragment:
if (srvPtr)
{
uintptr_t resource = reinterpret_cast<uintptr_t>(GetViewResource(srvPtr));
unsetConflictingUAVs(gl::PipelineType::GraphicsPipeline,
gl::ShaderType::Compute, resource, nullptr);
}
deviceContext->PSSetShaderResources(resourceSlot, 1, &srvPtr);
break;
case gl::ShaderType::Compute:
......@@ -758,9 +817,13 @@ void StateManager11::setUnorderedAccessViewInternal(gl::ShaderType shaderType,
ID3D11UnorderedAccessView *uavPtr = uav ? uav->get() : nullptr;
// We need to make sure that resource being set to UnorderedAccessView slot |resourceSlot|
// is not bound on SRV.
if (uavPtr && unsetConflictingView(uavPtr))
if (uavPtr)
{
mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
uintptr_t resource = reinterpret_cast<uintptr_t>(GetViewResource(uavPtr));
unsetConflictingSRVs(gl::PipelineType::ComputePipeline, gl::ShaderType::Vertex,
resource, nullptr, false);
unsetConflictingSRVs(gl::PipelineType::ComputePipeline, gl::ShaderType::Fragment,
resource, nullptr, false);
}
deviceContext->CSSetUnorderedAccessViews(resourceSlot, 1, &uavPtr, nullptr);
......@@ -831,10 +894,16 @@ angle::Result StateManager11::updateStateForCompute(const gl::Context *context,
auto dirtyBitsCopy = mInternalDirtyBits & mComputeDirtyBitsMask;
mInternalDirtyBits &= ~mComputeDirtyBitsMask;
for (auto dirtyBit : dirtyBitsCopy)
for (auto iter = dirtyBitsCopy.begin(), end = dirtyBitsCopy.end(); iter != end; ++iter)
{
switch (dirtyBit)
switch (*iter)
{
case DIRTY_BIT_COMPUTE_SRVUAV_STATE:
// Avoid to call syncTexturesForCompute function two times.
iter.resetLaterBit(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
ANGLE_TRY(syncTexturesForCompute(context));
break;
case DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE:
ANGLE_TRY(syncTexturesForCompute(context));
break;
......@@ -1638,9 +1707,14 @@ void StateManager11::invalidateIndexBuffer()
void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv)
{
if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv)))
if (rtv)
{
mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
unsetConflictingView(gl::PipelineType::GraphicsPipeline, rtv, true);
}
if (dsv)
{
unsetConflictingView(gl::PipelineType::GraphicsPipeline, dsv, true);
}
mRenderer->getDeviceContext()->OMSetRenderTargets(1, &rtv, dsv);
......@@ -1651,21 +1725,14 @@ void StateManager11::setRenderTargets(ID3D11RenderTargetView **rtvs,
UINT numRTVs,
ID3D11DepthStencilView *dsv)
{
bool anyDirty = false;
for (UINT rtvIndex = 0; rtvIndex < numRTVs; ++rtvIndex)
{
anyDirty = anyDirty || unsetConflictingView(rtvs[rtvIndex]);
unsetConflictingView(gl::PipelineType::GraphicsPipeline, rtvs[rtvIndex], true);
}
if (dsv)
{
anyDirty = anyDirty || unsetConflictingView(dsv);
}
if (anyDirty)
{
mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
unsetConflictingView(gl::PipelineType::GraphicsPipeline, dsv, true);
}
mRenderer->getDeviceContext()->OMSetRenderTargets(numRTVs, (numRTVs > 0) ? rtvs : nullptr, dsv);
......@@ -1791,20 +1858,26 @@ angle::Result StateManager11::clearUAVs(gl::ShaderType shaderType,
return angle::Result::Continue;
}
bool StateManager11::unsetConflictingView(ID3D11View *view)
void StateManager11::unsetConflictingView(gl::PipelineType pipeline,
ID3D11View *view,
bool isRenderTarget)
{
uintptr_t resource = reinterpret_cast<uintptr_t>(GetViewResource(view));
return unsetConflictingSRVs(gl::ShaderType::Vertex, resource, nullptr) ||
unsetConflictingSRVs(gl::ShaderType::Fragment, resource, nullptr) ||
unsetConflictingSRVs(gl::ShaderType::Compute, resource, nullptr);
unsetConflictingSRVs(pipeline, gl::ShaderType::Vertex, resource, nullptr, isRenderTarget);
unsetConflictingSRVs(pipeline, gl::ShaderType::Fragment, resource, nullptr, isRenderTarget);
unsetConflictingSRVs(pipeline, gl::ShaderType::Compute, resource, nullptr, isRenderTarget);
unsetConflictingUAVs(pipeline, gl::ShaderType::Compute, resource, nullptr);
}
bool StateManager11::unsetConflictingSRVs(gl::ShaderType shaderType,
void StateManager11::unsetConflictingSRVs(gl::PipelineType pipeline,
gl::ShaderType shaderType,
uintptr_t resource,
const gl::ImageIndex *index)
const gl::ImageIndex *index,
bool isRenderTarget)
{
auto *currentSRVs = getSRVCache(shaderType);
gl::PipelineType conflictPipeline = gl::GetPipelineType(shaderType);
bool foundOne = false;
for (size_t resourceIndex = 0; resourceIndex < currentSRVs->size(); ++resourceIndex)
......@@ -1820,7 +1893,48 @@ bool StateManager11::unsetConflictingSRVs(gl::ShaderType shaderType,
}
}
return foundOne;
if (foundOne && (pipeline != conflictPipeline || isRenderTarget))
{
switch (conflictPipeline)
{
case gl::PipelineType::GraphicsPipeline:
mInternalDirtyBits.set(DIRTY_BIT_GRAPHICS_SRVUAV_STATE);
break;
case gl::PipelineType::ComputePipeline:
mInternalDirtyBits.set(DIRTY_BIT_COMPUTE_SRVUAV_STATE);
break;
default:
UNREACHABLE();
}
}
}
void StateManager11::unsetConflictingUAVs(gl::PipelineType pipeline,
gl::ShaderType shaderType,
uintptr_t resource,
const gl::ImageIndex *index)
{
ASSERT(shaderType == gl::ShaderType::Compute);
bool foundOne = false;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
for (size_t resourceIndex = 0; resourceIndex < mCurComputeUAVs.size(); ++resourceIndex)
{
auto &record = mCurComputeUAVs[resourceIndex];
if (record.view && record.resource == resource &&
(!index || ImageIndexConflictsWithUAV(*index, record.desc)))
{
deviceContext->CSSetUnorderedAccessViews(resourceIndex, 1, &mNullUAVs[0], nullptr);
mCurComputeUAVs.update(resourceIndex, nullptr);
foundOne = true;
}
}
if (foundOne && pipeline == gl::PipelineType::GraphicsPipeline)
{
mInternalDirtyBits.set(DIRTY_BIT_COMPUTE_SRVUAV_STATE);
}
}
void StateManager11::unsetConflictingAttachmentResources(
......@@ -1834,14 +1948,26 @@ void StateManager11::unsetConflictingAttachmentResources(
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::ShaderType::Vertex, resourcePtr, &index);
unsetConflictingSRVs(gl::ShaderType::Fragment, resourcePtr, &index);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Vertex,
resourcePtr, &index, false);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Fragment,
resourcePtr, &index, false);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Compute,
resourcePtr, &index, false);
unsetConflictingUAVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Compute,
resourcePtr, &index);
}
else if (attachment.type() == GL_FRAMEBUFFER_DEFAULT)
{
uintptr_t resourcePtr = reinterpret_cast<uintptr_t>(resource);
unsetConflictingSRVs(gl::ShaderType::Vertex, resourcePtr, nullptr);
unsetConflictingSRVs(gl::ShaderType::Fragment, resourcePtr, nullptr);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Vertex,
resourcePtr, nullptr, false);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Fragment,
resourcePtr, nullptr, false);
unsetConflictingSRVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Compute,
resourcePtr, nullptr, false);
unsetConflictingUAVs(gl::PipelineType::GraphicsPipeline, gl::ShaderType::Compute,
resourcePtr, nullptr);
}
}
......@@ -2188,12 +2314,12 @@ angle::Result StateManager11::updateState(const gl::Context *context,
}
}
auto dirtyBitsCopy = mInternalDirtyBits;
mInternalDirtyBits.reset();
auto dirtyBitsCopy = mInternalDirtyBits & mGraphicsDirtyBitsMask;
mInternalDirtyBits &= ~mGraphicsDirtyBitsMask;
for (auto dirtyBit : dirtyBitsCopy)
for (auto iter = dirtyBitsCopy.begin(), end = dirtyBitsCopy.end(); iter != end; ++iter)
{
switch (dirtyBit)
switch (*iter)
{
case DIRTY_BIT_RENDER_TARGET:
ANGLE_TRY(syncFramebuffer(context));
......@@ -2214,6 +2340,10 @@ angle::Result StateManager11::updateState(const gl::Context *context,
case DIRTY_BIT_DEPTH_STENCIL_STATE:
ANGLE_TRY(syncDepthStencilState(context));
break;
case DIRTY_BIT_GRAPHICS_SRVUAV_STATE:
iter.resetLaterBit(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
ANGLE_TRY(syncTextures(context));
break;
case DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE:
// TODO(jmadill): More fine-grained update.
ANGLE_TRY(syncTextures(context));
......@@ -2257,8 +2387,9 @@ angle::Result StateManager11::updateState(const gl::Context *context,
}
}
// Check that we haven't set any dirty bits in the flushing of the dirty bits loop.
ASSERT(mInternalDirtyBits.none());
// Check that we haven't set any dirty bits in the flushing of the dirty bits loop, except
// DIRTY_BIT_COMPUTE_SRVUAV_STATE dirty bit.
ASSERT((mInternalDirtyBits & mGraphicsDirtyBitsMask).none());
return angle::Result::Continue;
}
......@@ -3621,9 +3752,9 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex
// We need to make sure that resource being set to UnorderedAccessView slot |registerIndex|
// is not bound on SRV.
if (uavPtr && unsetConflictingView(uavPtr->get()))
if (uavPtr)
{
mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
unsetConflictingView(gl::GetPipelineType(shaderType), uavPtr->get(), false);
}
const unsigned int registerIndex = mProgramD3D->getShaderStorageBufferRegisterIndex(
......@@ -3718,9 +3849,9 @@ angle::Result StateManager11::syncAtomicCounterBuffersForShader(const gl::Contex
// We need to make sure that resource being set to UnorderedAccessView slot |registerIndex|
// is not bound on SRV.
if (uavPtr && unsetConflictingView(uavPtr->get()))
if (uavPtr)
{
mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
unsetConflictingView(gl::GetPipelineType(shaderType), uavPtr->get(), false);
}
const unsigned int registerIndex =
......
......@@ -296,10 +296,17 @@ class StateManager11 final : angle::NonCopyable
UINT resourceSlot,
const UAVType *uav);
bool unsetConflictingView(ID3D11View *view);
bool unsetConflictingSRVs(gl::ShaderType shaderType,
void unsetConflictingView(gl::PipelineType pipeline, ID3D11View *view, bool isRenderTarget);
void unsetConflictingSRVs(gl::PipelineType pipeline,
gl::ShaderType shaderType,
uintptr_t resource,
const gl::ImageIndex *index,
bool isRenderTarget);
void unsetConflictingUAVs(gl::PipelineType pipeline,
gl::ShaderType shaderType,
uintptr_t resource,
const gl::ImageIndex *index);
void unsetConflictingAttachmentResources(const gl::FramebufferAttachment &attachment,
ID3D11Resource *resource);
......@@ -428,6 +435,10 @@ class StateManager11 final : angle::NonCopyable
// DIRTY_BIT_SHADERS and DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE should be dealt before
// DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS for update image layers.
DIRTY_BIT_SHADERS,
// DIRTY_BIT_GRAPHICS_SRVUAV_STATE and DIRTY_BIT_COMPUTE_SRVUAV_STATE should be lower
// bits than DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE.
DIRTY_BIT_GRAPHICS_SRVUAV_STATE,
DIRTY_BIT_COMPUTE_SRVUAV_STATE,
DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE,
DIRTY_BIT_PROGRAM_UNIFORMS,
DIRTY_BIT_DRIVER_UNIFORMS,
......@@ -448,6 +459,7 @@ class StateManager11 final : angle::NonCopyable
// Internal dirty bits.
DirtyBits mInternalDirtyBits;
DirtyBits mGraphicsDirtyBitsMask;
DirtyBits mComputeDirtyBitsMask;
// Blend State
......
......@@ -2790,9 +2790,6 @@ void main()
// 2. DrawArrays.
TEST_P(ComputeShaderTest, DispatchDraw)
{
// TODO(xinghua.cao@intel.com): http://anglebug.com/3152
ANGLE_SKIP_TEST_IF(IsD3D11());
const char kCSSource[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
......@@ -2860,9 +2857,6 @@ void main(void) {
// 4. DrawArrays.
TEST_P(ComputeShaderTest, DrawDispachDispatchDraw)
{
// TODO(xinghua.cao@intel.com): http://anglebug.com/3152
ANGLE_SKIP_TEST_IF(IsD3D11());
const char kCSSource[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
......@@ -2939,9 +2933,6 @@ void main(void) {
// 4. DispatchCompute.
TEST_P(ComputeShaderTest, DispatchDrawDrawDispatch)
{
// TODO(xinghua.cao@intel.com): http://anglebug.com/3152
ANGLE_SKIP_TEST_IF(IsD3D11());
const char kCSSource[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
......
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