Commit b16d69c3 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Add support for surface multisampling

A multisample image is created for the surface if multisampling is enabled. Prior to present, this multisample image is resolved into the swapchain image. FramebufferVk::readPixelsImpl similarly has got the ability to resolve the region of interest into a temporary image prior to readback. Tests are added to render a point, line and a triangle on a 4x multisampled surface. Bug: angleproject:3204 Change-Id: I34aca502fa1918b5cbf000ff11521c350372e051 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1610188Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent cd3011fb
...@@ -23,8 +23,6 @@ namespace gl ...@@ -23,8 +23,6 @@ namespace gl
struct Extensions; struct Extensions;
typedef std::set<GLuint> SupportedSampleSet;
struct TextureCaps struct TextureCaps
{ {
TextureCaps(); TextureCaps();
......
...@@ -466,6 +466,8 @@ using UniformBuffersArray = std::array<T, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BIND ...@@ -466,6 +466,8 @@ using UniformBuffersArray = std::array<T, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BIND
using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>; using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
using SupportedSampleSet = std::set<GLuint>;
// OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than // OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than
// the size of the bound buffer. This function reduces the returned size to fit the bound buffer if // the size of the bound buffer. This function reduces the returned size to fit the bound buffer if
// necessary. Returns 0 if no buffer is bound or if integer overflow occurs. // necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
......
...@@ -685,6 +685,16 @@ void ContextVk::updateColorMask(const gl::BlendState &blendState) ...@@ -685,6 +685,16 @@ void ContextVk::updateColorMask(const gl::BlendState &blendState)
framebufferVk->getEmulatedAlphaAttachmentMask()); framebufferVk->getEmulatedAlphaAttachmentMask());
} }
void ContextVk::updateSampleMask(const gl::State &glState)
{
for (uint32_t maskNumber = 0; maskNumber < glState.getMaxSampleMaskWords(); ++maskNumber)
{
static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
uint32_t mask = glState.isSampleMaskEnabled() ? glState.getSampleMaskWord(maskNumber) : 0;
mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, maskNumber, mask);
}
}
void ContextVk::updateViewport(FramebufferVk *framebufferVk, void ContextVk::updateViewport(FramebufferVk *framebufferVk,
const gl::Rectangle &viewport, const gl::Rectangle &viewport,
float nearPlane, float nearPlane,
...@@ -789,14 +799,43 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -789,14 +799,43 @@ angle::Result ContextVk::syncState(const gl::Context *context,
updateColorMask(glState.getBlendState()); updateColorMask(glState.getBlendState());
break; break;
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
&mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
break; break;
case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
// TODO(syoussefi): glSampleCoverage and `GL_SAMPLE_COVERAGE` have a similar
// behavior to alphaToCoverage, without native support in Vulkan. Sample coverage
// results in a mask that's applied *on top of* alphaToCoverage. More importantly,
// glSampleCoverage can choose to invert the applied mask; a feature that's not
// easily emulatable. For example, say there are 4 samples {0, 1, 2, 3} and
// alphaToCoverage (both in GL and Vulkan, as well as sampleCoverage in GL) is
// implemented such that the alpha value selects the set of samples
// {0, ..., round(alpha * 4)}. With glSampleCoverage, an application can blend two
// object LODs as such the following, covering all samples in a pixel:
//
// glSampleCoverage(0.5, GL_FALSE); // covers samples {0, 1}
// drawLOD0();
// glSampleCoverage(0.5, GL_TRUE); // covers samples {2, 3}
// drawLOD1();
//
// In Vulkan, it's not possible to restrict drawing to samples {2, 3} through
// alphaToCoverage alone.
//
// One way to acheive this behavior is to modify the shader to output to
// gl_SampleMask with values we emulate for sample coverage, taking inversion
// into account.
//
// http://anglebug.com/3204
break; break;
case gl::State::DIRTY_BIT_SAMPLE_COVERAGE: case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
// TODO(syoussefi): See DIRTY_BIT_SAMPLE_COVERAGE_ENABLED.
// http://anglebug.com/3204
break; break;
case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED: case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED:
updateSampleMask(glState);
break; break;
case gl::State::DIRTY_BIT_SAMPLE_MASK: case gl::State::DIRTY_BIT_SAMPLE_MASK:
updateSampleMask(glState);
break; break;
case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition, mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
...@@ -919,6 +958,9 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -919,6 +958,9 @@ angle::Result ContextVk::syncState(const gl::Context *context,
updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(), updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane(), isViewportFlipEnabledForDrawFBO()); glState.getFarPlane(), isViewportFlipEnabledForDrawFBO());
updateColorMask(glState.getBlendState()); updateColorMask(glState.getBlendState());
updateSampleMask(glState);
mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
mDrawFramebuffer->getSamples());
mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition, mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
glState.getRasterizerState()); glState.getRasterizerState());
updateScissor(glState); updateScissor(glState);
...@@ -987,8 +1029,16 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -987,8 +1029,16 @@ angle::Result ContextVk::syncState(const gl::Context *context,
case gl::State::DIRTY_BIT_IMAGE_BINDINGS: case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
break; break;
case gl::State::DIRTY_BIT_MULTISAMPLING: case gl::State::DIRTY_BIT_MULTISAMPLING:
// TODO(syoussefi): this should configure the pipeline to render as if
// single-sampled, and write the results to all samples of a pixel regardless of
// coverage. See EXT_multisample_compatibility. http://anglebug.com/3204
break; break;
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE: case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
// TODO(syoussefi): this is part of EXT_multisample_compatibility. The alphaToOne
// Vulkan feature should be enabled to support this extension.
// http://anglebug.com/3204
mGraphicsPipelineDesc->updateAlphaToOneEnable(&mGraphicsPipelineTransition,
glState.isSampleAlphaToOneEnabled());
break; break;
case gl::State::DIRTY_BIT_COVERAGE_MODULATION: case gl::State::DIRTY_BIT_COVERAGE_MODULATION:
break; break;
......
...@@ -207,6 +207,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -207,6 +207,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
gl::TextureType type, gl::TextureType type,
gl::Texture **textureOut); gl::Texture **textureOut);
void updateColorMask(const gl::BlendState &blendState); void updateColorMask(const gl::BlendState &blendState);
void updateSampleMask(const gl::State &glState);
void handleError(VkResult errorCode, void handleError(VkResult errorCode,
const char *file, const char *file,
......
...@@ -1169,6 +1169,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1169,6 +1169,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
{ {
TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl"); TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl");
RendererVk *renderer = contextVk->getRenderer();
ANGLE_TRY(renderTarget->ensureImageInitialized(contextVk)); ANGLE_TRY(renderTarget->ensureImageInitialized(contextVk));
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
...@@ -1186,6 +1188,56 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1186,6 +1188,56 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags); readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
} }
size_t level = renderTarget->getLevelIndex();
size_t layer = renderTarget->getLayerIndex();
VkOffset3D srcOffset = {area.x, area.y, 0};
VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
1};
// If the source image is multisampled, we need to resolve it into a temporary image before
// performing a readback.
bool isMultisampled = srcImage->getSamples() > 1;
vk::Scoped<vk::ImageHelper> resolvedImage(contextVk->getDevice());
if (isMultisampled)
{
ANGLE_TRY(resolvedImage.get().init2DStaging(
contextVk, renderer->getMemoryProperties(), gl::Extents(area.width, area.height, 1),
srcImage->getFormat(),
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 1));
resolvedImage.get().updateQueueSerial(renderer->getCurrentQueueSerial());
// TODO(syoussefi): resolve only works on color images (not depth/stencil). If readback
// on multisampled depth/stencil image is done, we would need a different path. One
// possible solution would be a compute shader that directly reads from the multisampled
// image, performs the resolve and outputs to the buffer in one go.
// http://anglebug.com/3200
ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
VkImageResolve resolveRegion = {};
resolveRegion.srcSubresource.aspectMask = copyAspectFlags;
resolveRegion.srcSubresource.mipLevel = level;
resolveRegion.srcSubresource.baseArrayLayer = layer;
resolveRegion.srcSubresource.layerCount = 1;
resolveRegion.srcOffset = srcOffset;
resolveRegion.dstSubresource.aspectMask = copyAspectFlags;
resolveRegion.dstSubresource.mipLevel = 0;
resolveRegion.dstSubresource.baseArrayLayer = 0;
resolveRegion.dstSubresource.layerCount = 1;
resolveRegion.dstOffset = {};
resolveRegion.extent = srcExtent;
srcImage->resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
resolvedImage.get().changeLayout(copyAspectFlags, vk::ImageLayout::TransferSrc,
commandBuffer);
// Make the resolved image the target of buffer copy.
srcImage = &resolvedImage.get();
level = 0;
layer = 0;
srcOffset = {0, 0, 0};
}
VkBuffer bufferHandle = VK_NULL_HANDLE; VkBuffer bufferHandle = VK_NULL_HANDLE;
uint8_t *readPixelBuffer = nullptr; uint8_t *readPixelBuffer = nullptr;
VkDeviceSize stagingOffset = 0; VkDeviceSize stagingOffset = 0;
...@@ -1195,19 +1247,15 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1195,19 +1247,15 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
&stagingOffset, nullptr)); &stagingOffset, nullptr));
VkBufferImageCopy region = {}; VkBufferImageCopy region = {};
region.bufferImageHeight = area.height; region.bufferImageHeight = srcExtent.height;
region.bufferOffset = stagingOffset; region.bufferOffset = stagingOffset;
region.bufferRowLength = area.width; region.bufferRowLength = srcExtent.width;
region.imageExtent.width = area.width; region.imageExtent = srcExtent;
region.imageExtent.height = area.height; region.imageOffset = srcOffset;
region.imageExtent.depth = 1;
region.imageOffset.x = area.x;
region.imageOffset.y = area.y;
region.imageOffset.z = 0;
region.imageSubresource.aspectMask = copyAspectFlags; region.imageSubresource.aspectMask = copyAspectFlags;
region.imageSubresource.baseArrayLayer = renderTarget->getLayerIndex(); region.imageSubresource.baseArrayLayer = layer;
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = renderTarget->getLevelIndex(); region.imageSubresource.mipLevel = level;
commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(), commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(),
bufferHandle, 1, &region); bufferHandle, 1, &region);
......
...@@ -262,6 +262,15 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer) ...@@ -262,6 +262,15 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer)
params->queryCount); params->queryCount);
break; break;
} }
case CommandID::ResolveImage:
{
const ResolveImageParams *params =
getParamPtr<ResolveImageParams>(currentCommand);
vkCmdResolveImage(cmdBuffer, params->srcImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, params->dstImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &params->region);
break;
}
case CommandID::SetEvent: case CommandID::SetEvent:
{ {
const SetEventParams *params = getParamPtr<SetEventParams>(currentCommand); const SetEventParams *params = getParamPtr<SetEventParams>(currentCommand);
......
...@@ -56,6 +56,7 @@ enum class CommandID : uint16_t ...@@ -56,6 +56,7 @@ enum class CommandID : uint16_t
PushConstants, PushConstants,
ResetEvent, ResetEvent,
ResetQueryPool, ResetQueryPool,
ResolveImage,
SetEvent, SetEvent,
WaitEvents, WaitEvents,
WriteTimestamp, WriteTimestamp,
...@@ -279,6 +280,14 @@ struct ResetQueryPoolParams ...@@ -279,6 +280,14 @@ struct ResetQueryPoolParams
}; };
VERIFY_4_BYTE_ALIGNMENT(ResetQueryPoolParams) VERIFY_4_BYTE_ALIGNMENT(ResetQueryPoolParams)
struct ResolveImageParams
{
VkImage srcImage;
VkImage dstImage;
VkImageResolve region;
};
VERIFY_4_BYTE_ALIGNMENT(ResolveImageParams)
struct BeginQueryParams struct BeginQueryParams
{ {
VkQueryPool queryPool; VkQueryPool queryPool;
...@@ -364,7 +373,7 @@ class SecondaryCommandBuffer final : angle::NonCopyable ...@@ -364,7 +373,7 @@ class SecondaryCommandBuffer final : angle::NonCopyable
const Image &dstImage, const Image &dstImage,
VkImageLayout dstImageLayout, VkImageLayout dstImageLayout,
uint32_t regionCount, uint32_t regionCount,
const VkImageBlit *pRegions, const VkImageBlit *regions,
VkFilter filter); VkFilter filter);
void clearAttachments(uint32_t attachmentCount, void clearAttachments(uint32_t attachmentCount,
...@@ -448,6 +457,13 @@ class SecondaryCommandBuffer final : angle::NonCopyable ...@@ -448,6 +457,13 @@ class SecondaryCommandBuffer final : angle::NonCopyable
void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
void resolveImage(const Image &srcImage,
VkImageLayout srcImageLayout,
const Image &dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageResolve *regions);
void setEvent(VkEvent event, VkPipelineStageFlags stageMask); void setEvent(VkEvent event, VkPipelineStageFlags stageMask);
void waitEvents(uint32_t eventCount, void waitEvents(uint32_t eventCount,
...@@ -676,7 +692,7 @@ ANGLE_INLINE void SecondaryCommandBuffer::blitImage(const Image &srcImage, ...@@ -676,7 +692,7 @@ ANGLE_INLINE void SecondaryCommandBuffer::blitImage(const Image &srcImage,
const Image &dstImage, const Image &dstImage,
VkImageLayout dstImageLayout, VkImageLayout dstImageLayout,
uint32_t regionCount, uint32_t regionCount,
const VkImageBlit *pRegions, const VkImageBlit *regions,
VkFilter filter) VkFilter filter)
{ {
// Currently ANGLE uses limited params so verify those assumptions and update if they change // Currently ANGLE uses limited params so verify those assumptions and update if they change
...@@ -687,7 +703,7 @@ ANGLE_INLINE void SecondaryCommandBuffer::blitImage(const Image &srcImage, ...@@ -687,7 +703,7 @@ ANGLE_INLINE void SecondaryCommandBuffer::blitImage(const Image &srcImage,
paramStruct->srcImage = srcImage.getHandle(); paramStruct->srcImage = srcImage.getHandle();
paramStruct->dstImage = dstImage.getHandle(); paramStruct->dstImage = dstImage.getHandle();
paramStruct->filter = filter; paramStruct->filter = filter;
paramStruct->region = pRegions[0]; paramStruct->region = regions[0];
} }
ANGLE_INLINE void SecondaryCommandBuffer::clearAttachments(uint32_t attachmentCount, ANGLE_INLINE void SecondaryCommandBuffer::clearAttachments(uint32_t attachmentCount,
...@@ -934,6 +950,23 @@ ANGLE_INLINE void SecondaryCommandBuffer::resetQueryPool(VkQueryPool queryPool, ...@@ -934,6 +950,23 @@ ANGLE_INLINE void SecondaryCommandBuffer::resetQueryPool(VkQueryPool queryPool,
paramStruct->queryCount = queryCount; paramStruct->queryCount = queryCount;
} }
ANGLE_INLINE void SecondaryCommandBuffer::resolveImage(const Image &srcImage,
VkImageLayout srcImageLayout,
const Image &dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageResolve *regions)
{
// Currently ANGLE uses limited params so verify those assumptions and update if they change.
ASSERT(srcImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
ASSERT(dstImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
ASSERT(regionCount == 1);
ResolveImageParams *paramStruct = initCommand<ResolveImageParams>(CommandID::ResolveImage);
paramStruct->srcImage = srcImage.getHandle();
paramStruct->dstImage = dstImage.getHandle();
paramStruct->region = regions[0];
}
ANGLE_INLINE void SecondaryCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask) ANGLE_INLINE void SecondaryCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask)
{ {
SetEventParams *paramStruct = initCommand<SetEventParams>(CommandID::SetEvent); SetEventParams *paramStruct = initCommand<SetEventParams>(CommandID::SetEvent);
......
...@@ -71,7 +71,8 @@ class OffscreenSurfaceVk : public SurfaceImpl ...@@ -71,7 +71,8 @@ class OffscreenSurfaceVk : public SurfaceImpl
angle::Result initialize(DisplayVk *displayVk, angle::Result initialize(DisplayVk *displayVk,
EGLint width, EGLint width,
EGLint height, EGLint height,
const vk::Format &vkFormat); const vk::Format &vkFormat,
GLint samples);
void destroy(const egl::Display *display); void destroy(const egl::Display *display);
vk::ImageHelper image; vk::ImageHelper image;
...@@ -164,6 +165,8 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -164,6 +165,8 @@ class WindowSurfaceVk : public SurfaceImpl
bool &swapchainOutOfDate); bool &swapchainOutOfDate);
angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects); angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects);
bool isMultiSampled() const;
VkSurfaceCapabilitiesKHR mSurfaceCaps; VkSurfaceCapabilitiesKHR mSurfaceCaps;
std::vector<VkPresentModeKHR> mPresentModes; std::vector<VkPresentModeKHR> mPresentModes;
...@@ -235,8 +238,14 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -235,8 +238,14 @@ class WindowSurfaceVk : public SurfaceImpl
std::array<SwapHistory, kSwapHistorySize> mSwapHistory; std::array<SwapHistory, kSwapHistorySize> mSwapHistory;
size_t mCurrentSwapHistoryIndex; size_t mCurrentSwapHistoryIndex;
// Depth/stencil image. Possibly multisampled.
vk::ImageHelper mDepthStencilImage; vk::ImageHelper mDepthStencilImage;
vk::ImageView mDepthStencilImageView; vk::ImageView mDepthStencilImageView;
// Multisample color image, view and framebuffer, if multisampling enabled.
vk::ImageHelper mColorImageMS;
vk::ImageView mColorImageViewMS;
vk::Framebuffer mFramebufferMS;
}; };
} // namespace rx } // namespace rx
......
...@@ -52,9 +52,7 @@ SurfaceImpl *DisplayVkAndroid::createWindowSurfaceVk(const egl::SurfaceState &st ...@@ -52,9 +52,7 @@ SurfaceImpl *DisplayVkAndroid::createWindowSurfaceVk(const egl::SurfaceState &st
egl::ConfigSet DisplayVkAndroid::generateConfigs() egl::ConfigSet DisplayVkAndroid::generateConfigs()
{ {
constexpr GLenum kColorFormats[] = {GL_RGBA8, GL_RGB8, GL_RGB565, GL_RGB10_A2, GL_RGBA16F}; constexpr GLenum kColorFormats[] = {GL_RGBA8, GL_RGB8, GL_RGB565, GL_RGB10_A2, GL_RGBA16F};
constexpr EGLint kSampleCounts[] = {0}; return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts,
this);
} }
bool DisplayVkAndroid::checkConfigSupport(egl::Config *config) bool DisplayVkAndroid::checkConfigSupport(egl::Config *config)
......
...@@ -34,9 +34,7 @@ SurfaceImpl *DisplayVkFuchsia::createWindowSurfaceVk(const egl::SurfaceState &st ...@@ -34,9 +34,7 @@ SurfaceImpl *DisplayVkFuchsia::createWindowSurfaceVk(const egl::SurfaceState &st
egl::ConfigSet DisplayVkFuchsia::generateConfigs() egl::ConfigSet DisplayVkFuchsia::generateConfigs()
{ {
constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX}; constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
constexpr EGLint kSampleCounts[] = {0}; return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts,
this);
} }
bool DisplayVkFuchsia::checkConfigSupport(egl::Config *config) bool DisplayVkFuchsia::checkConfigSupport(egl::Config *config)
......
...@@ -496,7 +496,7 @@ void GraphicsPipelineDesc::initDefaults() ...@@ -496,7 +496,7 @@ void GraphicsPipelineDesc::initDefaults()
mRasterizationAndMultisampleStateInfo.minSampleShading = 0.0f; mRasterizationAndMultisampleStateInfo.minSampleShading = 0.0f;
for (uint32_t &sampleMask : mRasterizationAndMultisampleStateInfo.sampleMask) for (uint32_t &sampleMask : mRasterizationAndMultisampleStateInfo.sampleMask)
{ {
sampleMask = 0; sampleMask = 0xFFFFFFFF;
} }
mRasterizationAndMultisampleStateInfo.bits.alphaToCoverageEnable = 0; mRasterizationAndMultisampleStateInfo.bits.alphaToCoverageEnable = 0;
mRasterizationAndMultisampleStateInfo.bits.alphaToOneEnable = 0; mRasterizationAndMultisampleStateInfo.bits.alphaToOneEnable = 0;
...@@ -850,6 +850,40 @@ void GraphicsPipelineDesc::updateLineWidth(GraphicsPipelineTransitionBits *trans ...@@ -850,6 +850,40 @@ void GraphicsPipelineDesc::updateLineWidth(GraphicsPipelineTransitionBits *trans
transition->set(ANGLE_GET_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo, lineWidth)); transition->set(ANGLE_GET_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo, lineWidth));
} }
void GraphicsPipelineDesc::updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
uint32_t rasterizationSamples)
{
mRasterizationAndMultisampleStateInfo.bits.rasterizationSamples = rasterizationSamples;
transition->set(ANGLE_GET_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo, bits));
}
void GraphicsPipelineDesc::updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition,
bool enable)
{
mRasterizationAndMultisampleStateInfo.bits.alphaToCoverageEnable = enable;
transition->set(ANGLE_GET_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo, bits));
}
void GraphicsPipelineDesc::updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition,
bool enable)
{
mRasterizationAndMultisampleStateInfo.bits.alphaToOneEnable = enable;
transition->set(ANGLE_GET_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo, bits));
}
void GraphicsPipelineDesc::updateSampleMask(GraphicsPipelineTransitionBits *transition,
uint32_t maskNumber,
uint32_t mask)
{
ASSERT(maskNumber < gl::MAX_SAMPLE_MASK_WORDS);
mRasterizationAndMultisampleStateInfo.sampleMask[maskNumber] = mask;
constexpr size_t kMaskBits =
sizeof(mRasterizationAndMultisampleStateInfo.sampleMask[0]) * kBitsPerByte;
transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mRasterizationAndMultisampleStateInfo,
sampleMask, maskNumber, kMaskBits));
}
void GraphicsPipelineDesc::updateBlendColor(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateBlendColor(GraphicsPipelineTransitionBits *transition,
const gl::ColorF &color) const gl::ColorF &color)
{ {
......
...@@ -195,11 +195,11 @@ struct RasterizationStateBits final ...@@ -195,11 +195,11 @@ struct RasterizationStateBits final
uint32_t polygonMode : 4; uint32_t polygonMode : 4;
uint32_t cullMode : 4; uint32_t cullMode : 4;
uint32_t frontFace : 4; uint32_t frontFace : 4;
uint32_t depthBiasEnable : 4; uint32_t depthBiasEnable : 1;
uint32_t rasterizationSamples : 4;
uint32_t sampleShadingEnable : 1; uint32_t sampleShadingEnable : 1;
uint32_t alphaToCoverageEnable : 1; uint32_t alphaToCoverageEnable : 1;
uint32_t alphaToOneEnable : 2; uint32_t alphaToOneEnable : 1;
uint32_t rasterizationSamples : 8;
}; };
constexpr size_t kRasterizationStateBitsSize = sizeof(RasterizationStateBits); constexpr size_t kRasterizationStateBitsSize = sizeof(RasterizationStateBits);
...@@ -384,6 +384,15 @@ class GraphicsPipelineDesc final ...@@ -384,6 +384,15 @@ class GraphicsPipelineDesc final
bool invertFrontFace); bool invertFrontFace);
void updateLineWidth(GraphicsPipelineTransitionBits *transition, float lineWidth); void updateLineWidth(GraphicsPipelineTransitionBits *transition, float lineWidth);
// Multisample states
void updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
uint32_t rasterizationSamples);
void updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition, bool enable);
void updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition, bool enable);
void updateSampleMask(GraphicsPipelineTransitionBits *transition,
uint32_t maskNumber,
uint32_t mask);
// RenderPass description. // RenderPass description.
const RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; } const RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
......
...@@ -323,13 +323,31 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats, ...@@ -323,13 +323,31 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats,
size_t colorFormatsCount, size_t colorFormatsCount,
const GLenum *depthStencilFormats, const GLenum *depthStencilFormats,
size_t depthStencilFormatCount, size_t depthStencilFormatCount,
const EGLint *sampleCounts,
size_t sampleCountsCount,
DisplayVk *display) DisplayVk *display)
{ {
ASSERT(colorFormatsCount > 0); ASSERT(colorFormatsCount > 0);
ASSERT(display != nullptr); ASSERT(display != nullptr);
gl::SupportedSampleSet colorSampleCounts;
gl::SupportedSampleSet depthStencilSampleCounts;
gl::SupportedSampleSet sampleCounts;
const VkPhysicalDeviceLimits &limits =
display->getRenderer()->getPhysicalDeviceProperties().limits;
const uint32_t depthStencilSampleCountsLimit =
limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts;
vk_gl::AddSampleCounts(limits.framebufferColorSampleCounts, &colorSampleCounts);
vk_gl::AddSampleCounts(depthStencilSampleCountsLimit, &depthStencilSampleCounts);
// Always support 0 samples
colorSampleCounts.insert(0);
depthStencilSampleCounts.insert(0);
std::set_intersection(colorSampleCounts.begin(), colorSampleCounts.end(),
depthStencilSampleCounts.begin(), depthStencilSampleCounts.end(),
std::inserter(sampleCounts, sampleCounts.begin()));
egl::ConfigSet configSet; egl::ConfigSet configSet;
for (size_t colorFormatIdx = 0; colorFormatIdx < colorFormatsCount; colorFormatIdx++) for (size_t colorFormatIdx = 0; colorFormatIdx < colorFormatsCount; colorFormatIdx++)
...@@ -346,12 +364,22 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats, ...@@ -346,12 +364,22 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats,
ASSERT(depthStencilFormats[depthStencilFormatIdx] == GL_NONE || ASSERT(depthStencilFormats[depthStencilFormatIdx] == GL_NONE ||
depthStencilFormatInfo.sized); depthStencilFormatInfo.sized);
for (size_t sampleCountIndex = 0; sampleCountIndex < sampleCountsCount; const gl::SupportedSampleSet *configSampleCounts = &sampleCounts;
sampleCountIndex++) // If there is no depth/stencil buffer, use the color samples set.
if (depthStencilFormats[depthStencilFormatIdx] == GL_NONE)
{
configSampleCounts = &colorSampleCounts;
}
// If there is no color buffer, use the depth/stencil samples set.
else if (colorFormats[colorFormatIdx] == GL_NONE)
{
configSampleCounts = &depthStencilSampleCounts;
}
for (EGLint sampleCount : *configSampleCounts)
{ {
egl::Config config = egl::Config config = GenerateDefaultConfig(display->getRenderer(), colorFormatInfo,
GenerateDefaultConfig(display->getRenderer(), colorFormatInfo, depthStencilFormatInfo, sampleCount);
depthStencilFormatInfo, sampleCounts[sampleCountIndex]);
if (display->checkConfigSupport(&config)) if (display->checkConfigSupport(&config))
{ {
configSet.add(config); configSet.add(config);
......
...@@ -41,18 +41,15 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats, ...@@ -41,18 +41,15 @@ egl::ConfigSet GenerateConfigs(const GLenum *colorFormats,
size_t colorFormatsCount, size_t colorFormatsCount,
const GLenum *depthStencilFormats, const GLenum *depthStencilFormats,
size_t depthStencilFormatCount, size_t depthStencilFormatCount,
const EGLint *sampleCounts,
size_t sampleCountsCount,
DisplayVk *display); DisplayVk *display);
template <size_t ColorFormatCount, size_t DepthStencilFormatCount, size_t SampleCountsCount> template <size_t ColorFormatCount, size_t DepthStencilFormatCount>
egl::ConfigSet GenerateConfigs(const GLenum (&colorFormats)[ColorFormatCount], egl::ConfigSet GenerateConfigs(const GLenum (&colorFormats)[ColorFormatCount],
const GLenum (&depthStencilFormats)[DepthStencilFormatCount], const GLenum (&depthStencilFormats)[DepthStencilFormatCount],
const EGLint (&sampleCounts)[SampleCountsCount],
DisplayVk *display) DisplayVk *display)
{ {
return GenerateConfigs(colorFormats, ColorFormatCount, depthStencilFormats, return GenerateConfigs(colorFormats, ColorFormatCount, depthStencilFormats,
DepthStencilFormatCount, sampleCounts, SampleCountsCount, display); DepthStencilFormatCount, display);
} }
} // namespace egl_vk } // namespace egl_vk
......
...@@ -18,19 +18,6 @@ namespace rx ...@@ -18,19 +18,6 @@ namespace rx
{ {
namespace namespace
{ {
void AddSampleCounts(VkSampleCountFlags sampleCounts, gl::SupportedSampleSet *outSet)
{
// The possible bits are VK_SAMPLE_COUNT_n_BIT = n, with n = 1 << b. At the time of this
// writing, b is in [0, 6], however, we test all 32 bits in case the enum is extended.
for (unsigned int i = 0; i < 32; ++i)
{
if ((sampleCounts & (1 << i)) != 0)
{
outSet->insert(1 << i);
}
}
}
void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCaps *outTextureCaps) void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCaps *outTextureCaps)
{ {
const VkPhysicalDeviceLimits &physicalDeviceLimits = const VkPhysicalDeviceLimits &physicalDeviceLimits =
...@@ -52,15 +39,15 @@ void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCap ...@@ -52,15 +39,15 @@ void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCap
{ {
if (hasColorAttachmentFeatureBit) if (hasColorAttachmentFeatureBit)
{ {
AddSampleCounts(physicalDeviceLimits.framebufferColorSampleCounts, vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferColorSampleCounts,
&outTextureCaps->sampleCounts); &outTextureCaps->sampleCounts);
} }
if (hasDepthAttachmentFeatureBit) if (hasDepthAttachmentFeatureBit)
{ {
AddSampleCounts(physicalDeviceLimits.framebufferDepthSampleCounts, vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferDepthSampleCounts,
&outTextureCaps->sampleCounts); &outTextureCaps->sampleCounts);
AddSampleCounts(physicalDeviceLimits.framebufferStencilSampleCounts, vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferStencilSampleCounts,
&outTextureCaps->sampleCounts); &outTextureCaps->sampleCounts);
} }
} }
} }
......
...@@ -1842,6 +1842,18 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1842,6 +1842,18 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
return angle::Result::Continue; return angle::Result::Continue;
} }
void ImageHelper::resolve(ImageHelper *dest,
const VkImageResolve &region,
vk::CommandBuffer *commandBuffer)
{
ASSERT(mCurrentLayout == vk::ImageLayout::TransferSrc);
dest->changeLayout(region.dstSubresource.aspectMask, vk::ImageLayout::TransferDst,
commandBuffer);
commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest->getImage(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
void ImageHelper::removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index) void ImageHelper::removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index)
{ {
// Find any staged updates for this index and removes them from the pending list. // Find any staged updates for this index and removes them from the pending list.
......
...@@ -582,6 +582,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -582,6 +582,7 @@ class ImageHelper final : public CommandGraphResource
// Create a 2D[Array] for staging purposes. Used by: // Create a 2D[Array] for staging purposes. Used by:
// //
// - TextureVk::copySubImageImplWithDraw // - TextureVk::copySubImageImplWithDraw
// - FramebufferVk::readPixelsImpl
// //
angle::Result init2DStaging(Context *context, angle::Result init2DStaging(Context *context,
const MemoryProperties &memoryProperties, const MemoryProperties &memoryProperties,
...@@ -643,6 +644,10 @@ class ImageHelper final : public CommandGraphResource ...@@ -643,6 +644,10 @@ class ImageHelper final : public CommandGraphResource
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel); angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
// Resolve this image into a destination image. This image should be in the TransferSrc layout.
// The destination image is automatically transitioned into TransferDst.
void resolve(ImageHelper *dest, const VkImageResolve &region, vk::CommandBuffer *commandBuffer);
// Data staging // Data staging
void removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index); void removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index);
......
...@@ -825,4 +825,17 @@ void GetViewport(const gl::Rectangle &viewport, ...@@ -825,4 +825,17 @@ void GetViewport(const gl::Rectangle &viewport,
} }
} }
} // namespace gl_vk } // namespace gl_vk
namespace vk_gl
{
void AddSampleCounts(VkSampleCountFlags sampleCounts, gl::SupportedSampleSet *setOut)
{
// The possible bits are VK_SAMPLE_COUNT_n_BIT = n, with n = 1 << b. At the time of this
// writing, b is in [0, 6], however, we test all 32 bits in case the enum is extended.
for (unsigned long bit : angle::BitSet32<32>(sampleCounts))
{
setOut->insert(1 << bit);
}
}
} // namespace vk_gl
} // namespace rx } // namespace rx
...@@ -544,6 +544,12 @@ void GetViewport(const gl::Rectangle &viewport, ...@@ -544,6 +544,12 @@ void GetViewport(const gl::Rectangle &viewport,
VkViewport *viewportOut); VkViewport *viewportOut);
} // namespace gl_vk } // namespace gl_vk
namespace vk_gl
{
// Find set bits in sampleCounts and add the corresponding sample count to the set.
void AddSampleCounts(VkSampleCountFlags sampleCounts, gl::SupportedSampleSet *outSet);
} // namespace vk_gl
} // namespace rx } // namespace rx
#define ANGLE_VK_TRY(context, command) \ #define ANGLE_VK_TRY(context, command) \
......
...@@ -223,7 +223,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -223,7 +223,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
const Image &dstImage, const Image &dstImage,
VkImageLayout dstImageLayout, VkImageLayout dstImageLayout,
uint32_t regionCount, uint32_t regionCount,
VkImageBlit *pRegions, const VkImageBlit *regions,
VkFilter filter); VkFilter filter);
void clearColorImage(const Image &image, void clearColorImage(const Image &image,
...@@ -313,6 +313,12 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -313,6 +313,12 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
VkResult reset(); VkResult reset();
void resetEvent(VkEvent event, VkPipelineStageFlags stageMask); void resetEvent(VkEvent event, VkPipelineStageFlags stageMask);
void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
void resolveImage(const Image &srcImage,
VkImageLayout srcImageLayout,
const Image &dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageResolve *regions);
void waitEvents(uint32_t eventCount, void waitEvents(uint32_t eventCount,
const VkEvent *events, const VkEvent *events,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags srcStageMask,
...@@ -578,13 +584,13 @@ ANGLE_INLINE void CommandBuffer::blitImage(const Image &srcImage, ...@@ -578,13 +584,13 @@ ANGLE_INLINE void CommandBuffer::blitImage(const Image &srcImage,
const Image &dstImage, const Image &dstImage,
VkImageLayout dstImageLayout, VkImageLayout dstImageLayout,
uint32_t regionCount, uint32_t regionCount,
VkImageBlit *pRegions, const VkImageBlit *regions,
VkFilter filter) VkFilter filter)
{ {
ASSERT(valid() && srcImage.valid() && dstImage.valid()); ASSERT(valid() && srcImage.valid() && dstImage.valid());
ASSERT(regionCount == 1); ASSERT(regionCount == 1);
vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(), vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(),
dstImageLayout, 1, pRegions, filter); dstImageLayout, 1, regions, filter);
} }
ANGLE_INLINE VkResult CommandBuffer::begin(const VkCommandBufferBeginInfo &info) ANGLE_INLINE VkResult CommandBuffer::begin(const VkCommandBufferBeginInfo &info)
......
...@@ -35,9 +35,7 @@ SurfaceImpl *DisplayVkWin32::createWindowSurfaceVk(const egl::SurfaceState &stat ...@@ -35,9 +35,7 @@ SurfaceImpl *DisplayVkWin32::createWindowSurfaceVk(const egl::SurfaceState &stat
egl::ConfigSet DisplayVkWin32::generateConfigs() egl::ConfigSet DisplayVkWin32::generateConfigs()
{ {
constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX}; constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
constexpr EGLint kSampleCounts[] = {0}; return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts,
this);
} }
bool DisplayVkWin32::checkConfigSupport(egl::Config *config) bool DisplayVkWin32::checkConfigSupport(egl::Config *config)
......
...@@ -86,9 +86,7 @@ SurfaceImpl *DisplayVkXcb::createWindowSurfaceVk(const egl::SurfaceState &state, ...@@ -86,9 +86,7 @@ SurfaceImpl *DisplayVkXcb::createWindowSurfaceVk(const egl::SurfaceState &state,
egl::ConfigSet DisplayVkXcb::generateConfigs() egl::ConfigSet DisplayVkXcb::generateConfigs()
{ {
constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX}; constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
constexpr EGLint kSampleCounts[] = {0}; return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts,
this);
} }
bool DisplayVkXcb::checkConfigSupport(egl::Config *config) bool DisplayVkXcb::checkConfigSupport(egl::Config *config)
......
...@@ -80,6 +80,7 @@ angle_end2end_tests_sources = [ ...@@ -80,6 +80,7 @@ angle_end2end_tests_sources = [
"gl_tests/MipmapTest.cpp", "gl_tests/MipmapTest.cpp",
"gl_tests/MultiDrawTest.cpp", "gl_tests/MultiDrawTest.cpp",
"gl_tests/MultisampleCompatibilityTest.cpp", "gl_tests/MultisampleCompatibilityTest.cpp",
"gl_tests/MultisampleTest.cpp",
"gl_tests/MultithreadingTest.cpp", "gl_tests/MultithreadingTest.cpp",
"gl_tests/MultiviewDrawTest.cpp", "gl_tests/MultiviewDrawTest.cpp",
"gl_tests/media/pixel.inl", "gl_tests/media/pixel.inl",
......
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