Workaround for AMD [[raster_order_group()]] bug

Metal [[raster_order_group()]] does not work for read_write textures on
AMD when the render pass doesn't have a color attachment on slot 0. To
work around this we attach one of the PLS textures to
GL_COLOR_ATTACHMENT0, if there isn't one already.

Bug: angleproject:7792
Bug: angleproject:7803
Bug: angleproject:7818
Change-Id: I7567ed28ed30c7e3ca23dc52778ed90f2fdff965
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4004529
Reviewed-by: Kyle Piddington <kpiddington@apple.com>
Commit-Queue: Chris Dalton <chris@rive.app>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
This commit is contained in:
Chris Dalton
2022-11-03 11:49:33 -06:00
committed by Angle LUCI CQ
parent c904cba330
commit 9bd9c1c2ae
5 changed files with 108 additions and 38 deletions

View File

@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 314
#define ANGLE_SH_VERSION 315
enum ShShaderSpec
{
@@ -128,6 +128,11 @@ struct ShPixelLocalStorageOptions
// ShPixelLocalStorageType::ImageLoadStore only: Can we use rgba8/rgba8i/rgba8ui image formats?
// Or do we need to manually pack and unpack from r32i/r32ui?
bool supportsNativeRGBA8ImageFormats = false;
// anglebug.com/7792 -- Metal [[raster_order_group()]] does not work for read_write textures on
// AMD when the render pass doesn't have a color attachment on slot 0. To work around this we
// attach one of the PLS textures to GL_COLOR_ATTACHMENT0, if there isn't one already.
bool renderPassNeedsAMDRasterOrderGroupsWorkaround = false;
};
struct ShCompileOptions

View File

@@ -267,7 +267,7 @@ void PixelLocalStoragePlane::ensureBackingTextureIfMemoryless(Context *context,
ASSERT(mMemorylessTextureID.value == 0);
// Create a new texture that backs the memoryless plane.
context->genTextures(1, &mMemorylessTextureID);
mMemorylessTextureID = context->createTexture();
{
ScopedBindTexture2D scopedBindTexture2D(context, mMemorylessTextureID);
context->bindTexture(TextureType::_2D, mMemorylessTextureID);
@@ -282,9 +282,7 @@ void PixelLocalStoragePlane::ensureBackingTextureIfMemoryless(Context *context,
}
}
void PixelLocalStoragePlane::attachToDrawFramebuffer(Context *context,
Extents plsExtents,
GLenum colorAttachment) const
void PixelLocalStoragePlane::attachToDrawFramebuffer(Context *context, GLenum colorAttachment) const
{
ASSERT(!isDeinitialized());
ASSERT(mTextureRef != nullptr); // Call ensureBackingTextureIfMemoryless() first!
@@ -389,10 +387,7 @@ void PixelLocalStoragePlane::issueClearCommand(ClearCommands *clearCommands,
}
}
void PixelLocalStoragePlane::bindToImage(Context *context,
Extents plsExtents,
GLuint unit,
bool needsR32Packing) const
void PixelLocalStoragePlane::bindToImage(Context *context, GLuint unit, bool needsR32Packing) const
{
ASSERT(!isDeinitialized());
ASSERT(mTextureRef != nullptr); // Call ensureBackingTextureIfMemoryless() first!
@@ -577,17 +572,57 @@ class PixelLocalStorageImageLoadStore : public PixelLocalStorage
mSavedImageBindings.emplace_back(state.getImageUnit(i));
}
// Save the default framebuffer width/height so we can restore it during onEnd().
Framebuffer *framebuffer = state.getDrawFramebuffer();
mSavedFramebufferDefaultWidth = framebuffer->getDefaultWidth();
mSavedFramebufferDefaultHeight = framebuffer->getDefaultHeight();
Framebuffer *framebuffer = state.getDrawFramebuffer();
if (mPLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround)
{
// anglebug.com/7792 -- Metal [[raster_order_group()]] does not work for read_write
// textures on AMD when the render pass doesn't have a color attachment on slot 0. To
// work around this we attach one of the PLS textures to GL_COLOR_ATTACHMENT0, if there
// isn't one already.
mHadColorAttachment0 = framebuffer->getColorAttachment(0) != nullptr;
if (!mHadColorAttachment0)
{
// Remember the current draw buffer state so we can restore it during onEnd().
const DrawBuffersVector<GLenum> &appDrawBuffers =
framebuffer->getDrawBufferStates();
mSavedDrawBuffers.resize(appDrawBuffers.size());
std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
// Specify the framebuffer width/height explicitly in case we end up rendering exclusively
// to shader images.
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
plsExtents.width);
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
plsExtents.height);
// Turn off draw buffer 0.
if (mSavedDrawBuffers[0] != GL_NONE)
{
GLenum drawBuffer0 = mSavedDrawBuffers[0];
mSavedDrawBuffers[0] = GL_NONE;
context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
mSavedDrawBuffers.data());
mSavedDrawBuffers[0] = drawBuffer0;
}
// Attach one of the PLS textures to GL_COLOR_ATTACHMENT0.
for (GLsizei i = 0; i < n; ++i)
{
if (loadops[i] == GL_DISABLE_ANGLE)
{
continue;
}
getPlane(i).attachToDrawFramebuffer(context, GL_COLOR_ATTACHMENT0);
break;
}
}
}
else
{
// Save the default framebuffer width/height so we can restore it during onEnd().
mSavedFramebufferDefaultWidth = framebuffer->getDefaultWidth();
mSavedFramebufferDefaultHeight = framebuffer->getDefaultHeight();
// Specify the framebuffer width/height explicitly in case we end up rendering
// exclusively to shader images.
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
plsExtents.width);
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
plsExtents.height);
}
// Guard GL state and bind a scratch framebuffer in case we need to reallocate or clear any
// PLS planes.
@@ -622,13 +657,11 @@ class PixelLocalStorageImageLoadStore : public PixelLocalStorage
}
const PixelLocalStoragePlane &plane = getPlane(i);
ASSERT(!plane.isDeinitialized());
plane.bindToImage(context, plsExtents, i,
!mPLSOptions.supportsNativeRGBA8ImageFormats);
plane.bindToImage(context, i, !mPLSOptions.supportsNativeRGBA8ImageFormats);
if (loadop == GL_ZERO || loadop == GL_CLEAR_ANGLE)
{
plane.attachToDrawFramebuffer(
context, plsExtents,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(pendingClears.size()));
context, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(pendingClears.size()));
pendingClears.push_back(i); // Defer the clear for later.
}
}
@@ -684,11 +717,31 @@ class PixelLocalStorageImageLoadStore : public PixelLocalStorage
}
mSavedImageBindings.clear();
// Restore the default framebuffer width/height.
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
mSavedFramebufferDefaultWidth);
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
mSavedFramebufferDefaultHeight);
if (mPLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround)
{
if (!mHadColorAttachment0)
{
// Detach the PLS texture we attached to GL_COLOR_ATTACHMENT0.
context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
TextureTarget::_2D, TextureID(), 0);
// Restore the draw buffer state from before PLS was enabled.
if (mSavedDrawBuffers[0] != GL_NONE)
{
context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
mSavedDrawBuffers.data());
}
mSavedDrawBuffers.clear();
}
}
else
{
// Restore the default framebuffer width/height.
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
mSavedFramebufferDefaultWidth);
context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
mSavedFramebufferDefaultHeight);
}
// We need ALL_BARRIER_BITS during end() because GL_SHADER_IMAGE_ACCESS_BARRIER_BIT doesn't
// synchronize all types of memory accesses that can happen after the barrier.
@@ -705,9 +758,13 @@ class PixelLocalStorageImageLoadStore : public PixelLocalStorage
FramebufferID mScratchFramebufferForClearing{};
// Saved values to restore during onEnd().
std::vector<ImageUnit> mSavedImageBindings;
// If mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
bool mHadColorAttachment0;
DrawBuffersVector<GLenum> mSavedDrawBuffers;
// If !mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
GLint mSavedFramebufferDefaultWidth;
GLint mSavedFramebufferDefaultHeight;
std::vector<ImageUnit> mSavedImageBindings;
};
// Implements pixel local storage via framebuffer fetch.
@@ -786,7 +843,7 @@ class PixelLocalStorageFramebufferFetch : public PixelLocalStorage
// nothing else was attached at this point.
GLenum colorAttachment = GL_COLOR_ATTACHMENT0 + drawBufferIdx;
ASSERT(!framebuffer->getAttachment(context, colorAttachment));
plane.attachToDrawFramebuffer(context, plsExtents, colorAttachment);
plane.attachToDrawFramebuffer(context, colorAttachment);
plsDrawBuffers[drawBufferIdx] = colorAttachment;
if (hasIndexedBlendAndColorMask)

View File

@@ -79,7 +79,7 @@ class PixelLocalStoragePlane : angle::NonCopyable
bool getTextureImageExtents(const Context *, Extents *extents) const;
// Attaches this plane to the specified color attachment point on the current draw framebuffer.
void attachToDrawFramebuffer(Context *, Extents plsExtents, GLenum colorAttachment) const;
void attachToDrawFramebuffer(Context *, GLenum colorAttachment) const;
// Interface for clearing typed pixel local storage planes.
class ClearCommands
@@ -97,7 +97,7 @@ class PixelLocalStoragePlane : angle::NonCopyable
void issueClearCommand(ClearCommands *, int target, GLenum loadop) const;
// Binds this PLS plane to a texture image unit for image load/store shader operations.
void bindToImage(Context *, Extents plsExtents, GLuint unit, bool needsR32Packing) const;
void bindToImage(Context *, GLuint unit, bool needsR32Packing) const;
// Low-level access to the backing texture. The plane must not be memoryless or deinitialized.
const ImageIndex &getTextureImageIndex() const { return mTextureImageIndex; }

View File

@@ -1044,7 +1044,6 @@ void DisplayMtl::initializeExtensions() const
// Raster order groups are required to make PLS coherent when using read_write textures.
bool rasterOrderGroupsSupported = !mFeatures.disableRasterOrderGroups.enabled &&
!isAMD() && !isIntel() && // anglebug.com/7792
[mMetalDevice areRasterOrderGroupsSupported];
mNativePLSOptions.fragmentSyncType =
rasterOrderGroupsSupported ? ShFragmentSynchronizationType::RasterOrderGroups_Metal
@@ -1054,6 +1053,15 @@ void DisplayMtl::initializeExtensions() const
!mFeatures.disableRWTextureTier2Support.enabled &&
readWriteTextureTier == MTLReadWriteTextureTier2;
if (isAMD())
{
// anglebug.com/7792 -- [[raster_order_group()]] does not work for read_write
// textures on AMD when the render pass doesn't have a color attachment on slot 0.
// To work around this we attach one of the PLS textures to GL_COLOR_ATTACHMENT0, if
// there isn't one already.
mNativePLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround = true;
}
mNativeExtensions.shaderPixelLocalStorageANGLE = true;
mNativeExtensions.shaderPixelLocalStorageCoherentANGLE = rasterOrderGroupsSupported;
@@ -1063,11 +1071,8 @@ void DisplayMtl::initializeExtensions() const
gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES);
mNativeCaps.maxPixelLocalStoragePlanes =
gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES;
if (!isAMD()) // anglebug.com/7803
{
mNativeCaps.maxColorAttachmentsWithActivePixelLocalStorage =
gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
}
mNativeCaps.maxColorAttachmentsWithActivePixelLocalStorage =
gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
mNativeCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes =
gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES +
gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;

View File

@@ -895,5 +895,8 @@
// bits 24..31 from glClearValueuiv value don't work on Intel Metal.
7794 MAC INTEL METAL : PixelLocalStorageTest.ClearValues_r32/* = SKIP
// Flaky synchronization on Intel
7818 MAC INTEL METAL : PixelLocalStorageTest.Coherency/* = SKIP
// GL program cache failure with shader images.
7797 WIN OPENGL : PixelLocalStorageTest.ProgramCache/* = SKIP