Skip to content

Commit

Permalink
Improve current multisampled renderbuffer/texture support
Browse files Browse the repository at this point in the history
This is split off from a change to implement multisampled textures for
the Vulkan back-end, and will come before that change.  The changes
include:

- Make a common utility rx::GetSamplePosition() function.  D3D11 and
  Vulkan use the same standard sample positions/locations for 1, 2, 4,
  8, and 16 samples.  The D3D11 back-end has a utility function for
  this, which is being moved to a common location--for use by both the
  D3D11 and Vulkan back-ends.

- Texture::setStorageMultisample() handles converting the "requested number of
  samples" to the actual number of samples used (e.g. converting 3 to 4),
  supported by the underlying back-end).  The actual number used is stored in
  gl::TextureState::mImageDescs, for use by other GLES commands.

- Change some end2end tests to not make assumptions about the supported number
  of samples, but to properly query what is supported.

Bug: angleproject:3565
Bug: angleproject:4196
Change-Id: I1dc12fedd0f8fb4975f90d87486e443b069b7141
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1948535
Commit-Queue: Ian Elliott <ianelliott@google.com>
Reviewed-by: Ian Elliott <ianelliott@google.com>
  • Loading branch information
ianelliottus authored and Commit Bot committed Dec 5, 2019
1 parent 2719fa4 commit 5f85783
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 31 deletions.
8 changes: 8 additions & 0 deletions src/libANGLE/Renderbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ angle::Result Renderbuffer::setStorageMultisample(const Context *context,
size_t height)
{
ANGLE_TRY(orphanImages(context));
// TODO (ianelliott): Ensure that the following spec language is correctly implemented:
//
// the resulting value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal to
// samples and no more than the next larger sample count supported by the implementation.
//
// For example, if 2, 4, and 8 samples are supported, and if 5 samples are requested, ANGLE
// should use 8 samples, and return 8 when GL_RENDERBUFFER_SAMPLES is queried.
// http://anglebug.com/4196
ANGLE_TRY(
mImplementation->setStorageMultisample(context, samples, internalformat, width, height));

Expand Down
4 changes: 4 additions & 0 deletions src/libANGLE/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,10 @@ angle::Result Texture::setStorageMultisample(Context *context,
ANGLE_TRY(releaseTexImageInternal(context));
ANGLE_TRY(orphanImages(context));

// Potentially adjust "samples" to a supported value
const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
samples = formatCaps.getNearestSamples(samples);

ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
fixedSampleLocations));

Expand Down
2 changes: 1 addition & 1 deletion src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ angle::Result Framebuffer11::getSamplePosition(const gl::Context *context,
ASSERT(attachment);
GLsizei sampleCount = attachment->getSamples();

d3d11_gl::GetSamplePosition(sampleCount, index, xy);
rx::GetSamplePosition(sampleCount, index, xy);
return angle::Result::Continue;
}

Expand Down
24 changes: 0 additions & 24 deletions src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,6 @@ namespace d3d11_gl
{
namespace
{
// Standard D3D sample positions from
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx
using SamplePositionsArray = std::array<float, 32>;
static constexpr std::array<SamplePositionsArray, 5> kSamplePositions = {
{{{0.5f, 0.5f}},
{{0.75f, 0.75f, 0.25f, 0.25f}},
{{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}},
{{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f,
0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}},
{{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f,
0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f,
0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f,
0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}};

// TODO(xinghua.cao@intel.com): Get a more accurate limit.
static D3D_FEATURE_LEVEL kMinimumFeatureLevelForES31 = D3D_FEATURE_LEVEL_11_0;

Expand Down Expand Up @@ -1698,16 +1684,6 @@ void GenerateCaps(ID3D11Device *device,
#endif
}

void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy)
{
size_t indexKey = static_cast<size_t>(ceil(log2(sampleCount)));
ASSERT(indexKey < kSamplePositions.size() &&
(2 * index + 1) < kSamplePositions[indexKey].size());

xy[0] = kSamplePositions[indexKey][2 * index];
xy[1] = kSamplePositions[indexKey][2 * index + 1];
}

} // namespace d3d11_gl

namespace gl_d3d11
Expand Down
2 changes: 0 additions & 2 deletions src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ void GenerateCaps(ID3D11Device *device,
gl::Extensions *extensions,
gl::Limitations *limitations);

void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy);

D3D_FEATURE_LEVEL GetMinimumFeatureLevelForES31();

} // namespace d3d11_gl
Expand Down
39 changes: 39 additions & 0 deletions src/libANGLE/renderer/renderer_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ namespace rx

namespace
{
// Both D3D and Vulkan support the same set of standard sample positions for 1, 2, 4, 8, and 16
// samples. See:
//
// - https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx
//
// -
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#primsrast-multisampling
using SamplePositionsArray = std::array<float, 32>;
constexpr std::array<SamplePositionsArray, 5> kSamplePositions = {
{{{0.5f, 0.5f}},
{{0.75f, 0.75f, 0.25f, 0.25f}},
{{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}},
{{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f,
0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}},
{{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f,
0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f,
0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f,
0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}};

void CopyColor(gl::ColorF *color)
{
// No-op
Expand Down Expand Up @@ -781,4 +800,24 @@ void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features,
features->overrideFeatures(state.featureOverridesEnabled, true);
features->overrideFeatures(state.featureOverridesDisabled, false);
}

void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy)
{
if (sampleCount > 16)
{
// Vulkan (and D3D11) doesn't have standard sample positions for 32 and 64 samples (and no
// drivers are known to support that many samples)
xy[0] = 0.5f;
xy[1] = 0.5f;
}
else
{
size_t indexKey = static_cast<size_t>(gl::log2(sampleCount));
ASSERT(indexKey < kSamplePositions.size() &&
(2 * index + 1) < kSamplePositions[indexKey].size());

xy[0] = kSamplePositions[indexKey][2 * index];
xy[1] = kSamplePositions[indexKey][2 * index + 1];
}
}
} // namespace rx
2 changes: 2 additions & 0 deletions src/libANGLE/renderer/renderer_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, u
*(outIndices++) = inIndices[loopStartIndex];
}
}

void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy);
} // namespace rx

#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
33 changes: 29 additions & 4 deletions src/tests/gl_tests/FramebufferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,13 +889,26 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountMix)
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());

// Lookup the supported number of sample counts (rely on fact that ANGLE uses the same set of
// sample counts for textures and renderbuffers)
GLint numSampleCounts = 0;
std::vector<GLint> sampleCounts;
GLsizei queryBufferSize = 1;
glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
queryBufferSize, &numSampleCounts);
ANGLE_SKIP_TEST_IF((numSampleCounts < 2));
sampleCounts.resize(numSampleCounts);
queryBufferSize = numSampleCounts;
glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, queryBufferSize,
sampleCounts.data());

GLTexture mTexture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTexture.get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGBA8, 1, 1, true);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[0], GL_RGBA8, 1, 1, true);

GLRenderbuffer mRenderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer.get());
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_RGBA8, 1, 1);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCounts[1], GL_RGBA8, 1, 1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
mTexture.get(), 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER,
Expand All @@ -915,11 +928,23 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountTex)
GLFramebuffer mFramebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());

// Lookup the supported number of sample counts
GLint numSampleCounts = 0;
std::vector<GLint> sampleCounts;
GLsizei queryBufferSize = 1;
glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
queryBufferSize, &numSampleCounts);
ANGLE_SKIP_TEST_IF((numSampleCounts < 2));
sampleCounts.resize(numSampleCounts);
queryBufferSize = numSampleCounts;
glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, queryBufferSize,
sampleCounts.data());

GLTexture mTextures[2];
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[0].get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGBA8, 1, 1, true);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[0], GL_RGBA8, 1, 1, true);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[1].get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, GL_RGBA8, 1, 1, true);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[1], GL_RGBA8, 1, 1, true);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
mTextures[0].get(), 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE,
Expand Down
48 changes: 48 additions & 0 deletions src/tests/gl_tests/RenderbufferMultisampleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,53 @@ TEST_P(RenderbufferMultisampleTest, IntegerInternalformat)
}
}

// Ensure that the following spec language is correctly implemented:
//
// the resulting value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal to
// samples and no more than the next larger sample count supported by the implementation.
//
// For example, if 2, 4, and 8 samples are supported, if 5 samples are requested, ANGLE will
// use 8 samples, and return 8 when GL_RENDERBUFFER_SAMPLES is queried.
TEST_P(RenderbufferMultisampleTest, OddSampleCount)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);

glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
ASSERT_GL_NO_ERROR();

// Lookup the supported number of sample counts
GLint numSampleCounts = 0;
std::vector<GLint> sampleCounts;
GLsizei queryBufferSize = 1;
glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, queryBufferSize,
&numSampleCounts);
ANGLE_SKIP_TEST_IF((numSampleCounts < 2));
sampleCounts.resize(numSampleCounts);
queryBufferSize = numSampleCounts;
glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, queryBufferSize,
sampleCounts.data());

// Look for two sample counts that are not 1 apart (e.g. 2 and 4). Request a sample count
// that's between those two samples counts (e.g. 3) and ensure that GL_RENDERBUFFER_SAMPLES
// is the higher number.
for (int i = 1; i < numSampleCounts; i++)
{
if (sampleCounts[i - 1] > (sampleCounts[i] + 1))
{
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCounts[i] + 1, GL_RGBA8, 64,
64);
ASSERT_GL_NO_ERROR();
GLint renderbufferSamples = 0;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES,
&renderbufferSamples);
ASSERT_GL_NO_ERROR();
// TODO (ianelliott): Uncomment the following line once the implementation is fixed.
// http://anglebug.com/4196
// EXPECT_EQ(renderbufferSamples, sampleCounts[i-1]);
break;
}
}
}

ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(RenderbufferMultisampleTest);
} // namespace

0 comments on commit 5f85783

Please sign in to comment.