зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: Mipmap is unconditionally enabled in ANGLE
ANGLE always enables the Mipmap. The fix does redefining the image with mipmaps and replace the origin one only when it is necessary. Bug: angleproject:3737 Change-Id: Ia33a16fd7feae303fb114988059c4eec58c4232d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1750627 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Ian Elliott <ianelliott@google.com>
This commit is contained in:
Родитель
88a99e4382
Коммит
052167bc15
|
@ -163,3 +163,4 @@ Samsung Electronics, Inc.
|
|||
|
||||
Arm Ltd.
|
||||
Fei Yang
|
||||
Xinyi He
|
||||
|
|
|
@ -496,6 +496,28 @@ TextureTarget TextureState::getBaseImageTarget() const
|
|||
: NonCubeTextureTypeToTarget(mType);
|
||||
}
|
||||
|
||||
GLuint TextureState::getEnabledLevelCount() const
|
||||
{
|
||||
GLuint levelCount = 0;
|
||||
const GLuint baseLevel = getEffectiveBaseLevel();
|
||||
const GLuint maxLevel = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
|
||||
|
||||
// The mip chain will have either one or more sequential levels, or max levels,
|
||||
// but not a sparse one.
|
||||
for (size_t descIndex = baseLevel; descIndex < mImageDescs.size();)
|
||||
{
|
||||
if (!mImageDescs[descIndex].size.empty())
|
||||
{
|
||||
levelCount++;
|
||||
}
|
||||
descIndex = (mType == TextureType::CubeMap) ? descIndex + 6 : descIndex + 1;
|
||||
}
|
||||
// The original image already takes account into the levelCount.
|
||||
levelCount = std::min(maxLevel - baseLevel + 1, levelCount);
|
||||
|
||||
return levelCount;
|
||||
}
|
||||
|
||||
ImageDesc::ImageDesc()
|
||||
: ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
|
||||
{}
|
||||
|
|
|
@ -147,6 +147,9 @@ class TextureState final : private angle::NonCopyable
|
|||
void setGenerateMipmapHint(GLenum hint);
|
||||
GLenum getGenerateMipmapHint() const;
|
||||
|
||||
// Return the enabled mipmap level count.
|
||||
GLuint getEnabledLevelCount() const;
|
||||
|
||||
private:
|
||||
// Texture needs access to the ImageDesc functions.
|
||||
friend class Texture;
|
||||
|
|
|
@ -3003,7 +3003,7 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
|
|||
// already notified of content change).
|
||||
// Test: SimpleStateChangeTestES31.DispatchWithImageTextureTexSubImageThenDispatchAgain
|
||||
// http://anglebug.com/3539
|
||||
ANGLE_TRY(textureVk->ensureImageInitialized(this));
|
||||
ANGLE_TRY(textureVk->ensureImageInitialized(this, ImageMipLevels::EnabledLevels));
|
||||
|
||||
vk::ImageLayout imageLayout = vk::ImageLayout::AllGraphicsShadersWrite;
|
||||
if (program->isCompute())
|
||||
|
|
|
@ -57,7 +57,8 @@ egl::Error ImageVk::initialize(const egl::Display *display)
|
|||
// Make sure the texture has created its backing storage
|
||||
ASSERT(mContext != nullptr);
|
||||
ContextVk *contextVk = vk::GetImpl(mContext);
|
||||
ANGLE_TRY(ResultToEGL(textureVk->ensureImageInitialized(contextVk)));
|
||||
ANGLE_TRY(ResultToEGL(
|
||||
textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)));
|
||||
|
||||
mImage = &textureVk->getImage();
|
||||
|
||||
|
|
|
@ -341,7 +341,7 @@ angle::Result TextureVk::copyCompressedTexture(const gl::Context *context,
|
|||
|
||||
ANGLE_TRY(redefineImage(context, destIndex, vkFormat, size));
|
||||
|
||||
ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
return copySubImageImplWithTransfer(
|
||||
contextVk, destIndex, gl::Offset(0, 0, 0), vkFormat, sourceLevel, 0,
|
||||
|
@ -433,7 +433,7 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
|
|||
{
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
|
||||
ANGLE_TRY(source->ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(source->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
const vk::Format &sourceVkFormat = source->getImage().getFormat();
|
||||
const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
|
||||
|
@ -546,7 +546,7 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
|
|||
if (mImage->valid())
|
||||
{
|
||||
// Make sure any updates to the image are already flushed.
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
vk::CommandBuffer *commandBuffer;
|
||||
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
|
||||
|
@ -648,7 +648,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
|
|||
if (mImage->valid())
|
||||
{
|
||||
// Make sure any updates to the image are already flushed.
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
|
||||
{
|
||||
|
@ -953,15 +953,15 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
|
|||
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData");
|
||||
|
||||
// Make sure the source is initialized and it's images are flushed.
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
|
||||
|
||||
vk::BufferHelper *copyBuffer = nullptr;
|
||||
VkDeviceSize sourceCopyOffset = 0;
|
||||
|
||||
ANGLE_TRY(copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, area, ©Buffer,
|
||||
&sourceCopyOffset, outDataPtr));
|
||||
ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, area,
|
||||
©Buffer, &sourceCopyOffset, outDataPtr));
|
||||
|
||||
// Explicitly finish. If new use cases arise where we don't want to block we can change this.
|
||||
ANGLE_TRY(contextVk->finishImpl());
|
||||
|
@ -969,58 +969,6 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
|
|||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
|
||||
size_t sourceLevel,
|
||||
uint32_t layerCount,
|
||||
uint32_t baseLayer,
|
||||
const gl::Box &sourceArea,
|
||||
vk::BufferHelper **bufferOut,
|
||||
VkDeviceSize *bufferOffsetOut,
|
||||
uint8_t **outDataPtr)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBuffer");
|
||||
|
||||
const angle::Format &imageFormat = getImage().getFormat().actualImageFormat();
|
||||
size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * sourceArea.depth *
|
||||
imageFormat.pixelBytes * layerCount;
|
||||
|
||||
vk::CommandBuffer *commandBuffer = nullptr;
|
||||
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
|
||||
|
||||
// http://anglebug.com/3949: Need to handle DS combined aspect, will require copying D & S
|
||||
// separately. See ImageHelper::stageSubresourceUpdate for DS copy buff->image example.
|
||||
ASSERT(mImage->getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ||
|
||||
mImage->getAspectFlags() == VK_IMAGE_ASPECT_DEPTH_BIT ||
|
||||
mImage->getAspectFlags() == VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
// Transition the image to readable layout
|
||||
mImage->changeLayout(mImage->getAspectFlags(), vk::ImageLayout::TransferSrc, commandBuffer);
|
||||
|
||||
// Allocate staging buffer data
|
||||
ANGLE_TRY(mImage->allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr,
|
||||
bufferOut, bufferOffsetOut, nullptr));
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.bufferOffset = *bufferOffsetOut;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageExtent.width = sourceArea.width;
|
||||
region.imageExtent.height = sourceArea.height;
|
||||
region.imageExtent.depth = sourceArea.depth;
|
||||
region.imageOffset.x = sourceArea.x;
|
||||
region.imageOffset.y = sourceArea.y;
|
||||
region.imageOffset.z = sourceArea.z;
|
||||
region.imageSubresource.aspectMask = mImage->getAspectFlags();
|
||||
region.imageSubresource.baseArrayLayer = baseLayer;
|
||||
region.imageSubresource.layerCount = layerCount;
|
||||
region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
|
||||
|
||||
commandBuffer->copyImageToBuffer(mImage->getImage(), mImage->getCurrentLayout(),
|
||||
(*bufferOut)->getBuffer().getHandle(), 1, ®ion);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
@ -1060,7 +1008,11 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
|
|||
|
||||
angle::Result TextureVk::generateMipmap(const gl::Context *context)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
bool needRedefineImage = true;
|
||||
|
||||
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
|
||||
|
||||
// Some data is pending, or the image has not been defined at all yet
|
||||
if (!mImage->valid())
|
||||
|
@ -1068,8 +1020,9 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
|
|||
// Let's initialize the image so we can generate the next levels.
|
||||
if (mImage->hasStagedUpdates())
|
||||
{
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
|
||||
ASSERT(mImage->valid());
|
||||
needRedefineImage = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1078,13 +1031,41 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
|
|||
}
|
||||
}
|
||||
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
// Check whether the image is already full mipmap
|
||||
if (mImage->getLevelCount() == getMipLevelCount(ImageMipLevels::FullMipChain) &&
|
||||
mImage->getBaseLevel() == mState.getEffectiveBaseLevel())
|
||||
{
|
||||
needRedefineImage = false;
|
||||
}
|
||||
|
||||
if (needRedefineImage)
|
||||
{
|
||||
// Flush update if needed.
|
||||
if (mImage->hasStagedUpdates())
|
||||
{
|
||||
vk::CommandBuffer *commandBuffer = nullptr;
|
||||
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
|
||||
ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0),
|
||||
mImage->getLevelCount(), getNativeImageLayer(0),
|
||||
mImage->getLayerCount(), commandBuffer));
|
||||
}
|
||||
|
||||
// Redefine the images with mipmaps.
|
||||
// Copy image to the staging buffer and stage an update to the new one.
|
||||
ANGLE_TRY(copyImageDataToStagingBuffer(contextVk, baseLevelDesc, false,
|
||||
getNativeImageLayer(0), 0, mImage->getBaseLevel()));
|
||||
|
||||
onStagingBufferChange();
|
||||
|
||||
// Release the origin image and recreate it with new mipmap counts.
|
||||
releaseImage(contextVk);
|
||||
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
|
||||
}
|
||||
// Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
|
||||
// only.
|
||||
if (renderer->hasImageFormatFeatureBits(mImage->getFormat().vkImageFormat, kBlitFeatureFlags))
|
||||
{
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(mImage->generateMipmapsWithBlit(
|
||||
contextVk, mState.getMipmapMaxLevel() - mState.getEffectiveBaseLevel()));
|
||||
}
|
||||
|
@ -1096,6 +1077,46 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
|
|||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result TextureVk::copyImageDataToStagingBuffer(ContextVk *contextVk,
|
||||
const gl::ImageDesc &desc,
|
||||
bool ignoreLayerCount,
|
||||
uint32_t currentLayer,
|
||||
uint32_t sourceMipLevel,
|
||||
uint32_t stagingDstMipLevel)
|
||||
{
|
||||
const gl::Extents &baseLevelExtents = desc.size;
|
||||
const gl::InternalFormat &baseLevelFormat = *desc.format.info;
|
||||
|
||||
VkExtent3D updatedExtents;
|
||||
VkOffset3D offset = {0};
|
||||
uint32_t layerCount;
|
||||
gl_vk::GetExtentsAndLayerCount(mState.getType(), baseLevelExtents, &updatedExtents,
|
||||
&layerCount);
|
||||
gl::Box area(offset.x, offset.y, offset.z, updatedExtents.width, updatedExtents.height,
|
||||
updatedExtents.depth);
|
||||
// TODO: Refactor TextureVk::changeLevels() to avoid this workaround.
|
||||
if (ignoreLayerCount)
|
||||
{
|
||||
layerCount = 1;
|
||||
}
|
||||
|
||||
// Copy from the base level image to the staging buffer
|
||||
vk::BufferHelper *stagingBuffer = nullptr;
|
||||
VkDeviceSize stagingBufferOffset = 0;
|
||||
ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceMipLevel, layerCount, currentLayer,
|
||||
area, &stagingBuffer, &stagingBufferOffset, nullptr));
|
||||
|
||||
// Stage an update to the new image
|
||||
size_t bufferSize = updatedExtents.width * updatedExtents.height * updatedExtents.depth *
|
||||
baseLevelFormat.pixelBytes;
|
||||
|
||||
ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(contextVk, bufferSize, stagingDstMipLevel,
|
||||
currentLayer, layerCount, updatedExtents,
|
||||
offset, stagingBuffer, stagingBufferOffset));
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLevel)
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
|
@ -1171,35 +1192,14 @@ angle::Result TextureVk::changeLevels(ContextVk *contextVk, GLuint baseLevel, GL
|
|||
// First we populate the staging buffer with current level data
|
||||
const gl::ImageDesc &desc =
|
||||
mState.getImageDesc(gl::TextureTypeToTarget(mState.getType(), layer), level);
|
||||
const gl::Extents &glExtents = desc.size;
|
||||
const gl::InternalFormat &info = *desc.format.info;
|
||||
|
||||
// We need to adjust the source Vulkan level to reflect the previous base level.
|
||||
// vk level 0 previously aligned with whatever the base level was.
|
||||
uint32_t srcLevelVK = baseLevelChanged ? level - previousBaseLevel : level;
|
||||
ASSERT(srcLevelVK <= mImage->getLevelCount());
|
||||
|
||||
// Gather Vulkan dimensions based on our knowledge of image type here
|
||||
VkOffset3D vkOffset = {0};
|
||||
VkExtent3D vkExtent;
|
||||
uint32_t layerCountDontCare;
|
||||
gl_vk::GetExtentsAndLayerCount(mState.getType(), glExtents, &vkExtent,
|
||||
&layerCountDontCare);
|
||||
|
||||
// Now copy from the image to the staging buffer
|
||||
vk::BufferHelper *stagingBuffer = nullptr;
|
||||
VkDeviceSize stagingBufferOffset = 0;
|
||||
gl::Box area(vkOffset.x, vkOffset.y, vkOffset.z, vkExtent.width, vkExtent.height,
|
||||
vkExtent.depth);
|
||||
ANGLE_TRY(copyImageDataToBuffer(contextVk, srcLevelVK, 1, layer, area, &stagingBuffer,
|
||||
&stagingBufferOffset, nullptr));
|
||||
|
||||
// Stage an update to the new image that we will populate with existing mip levels
|
||||
// We're providing the buffer handle and offset to use, since we *just* populated it
|
||||
size_t bufferSize = vkExtent.width * vkExtent.height * vkExtent.depth * info.pixelBytes;
|
||||
ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(contextVk, bufferSize, level, layer,
|
||||
1, vkExtent, vkOffset, stagingBuffer,
|
||||
stagingBufferOffset));
|
||||
ANGLE_TRY(
|
||||
copyImageDataToStagingBuffer(contextVk, desc, true, layer, srcLevelVK, level));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1251,7 +1251,7 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
|
|||
ASSERT(imageIndex.getLevelIndex() >= 0);
|
||||
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
GLuint layerIndex = 0, layerCount = 0;
|
||||
GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex);
|
||||
|
@ -1264,11 +1264,11 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
|
|||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk)
|
||||
angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels)
|
||||
{
|
||||
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
|
||||
const gl::Extents &baseLevelExtents = baseLevelDesc.size;
|
||||
const uint32_t levelCount = getLevelCount() - mState.getEffectiveBaseLevel();
|
||||
const uint32_t levelCount = getMipLevelCount(mipLevels);
|
||||
|
||||
const vk::Format &format =
|
||||
contextVk->getRenderer()->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
|
||||
|
@ -1338,7 +1338,7 @@ angle::Result TextureVk::syncState(const gl::Context *context,
|
|||
}
|
||||
|
||||
// Initialize the image storage and flush the pixel buffer.
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
|
||||
|
||||
if (dirtyBits.none() && mSampler.valid())
|
||||
{
|
||||
|
@ -1635,7 +1635,22 @@ void TextureVk::releaseStagingBuffer(ContextVk *contextVk)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t TextureVk::getLevelCount() const
|
||||
uint32_t TextureVk::getMipLevelCount(ImageMipLevels mipLevels) const
|
||||
{
|
||||
switch (mipLevels)
|
||||
{
|
||||
case ImageMipLevels::EnabledLevels:
|
||||
return mState.getEnabledLevelCount();
|
||||
case ImageMipLevels::FullMipChain:
|
||||
return getMaxLevelCount() - mState.getEffectiveBaseLevel();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TextureVk::getMaxLevelCount() const
|
||||
{
|
||||
// getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
|
||||
return mState.getMipmapMaxLevel() + 1;
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
namespace rx
|
||||
{
|
||||
|
||||
enum class ImageMipLevels
|
||||
{
|
||||
EnabledLevels = 0,
|
||||
FullMipChain = 1,
|
||||
|
||||
InvalidEnum = 2,
|
||||
};
|
||||
|
||||
class TextureVk : public TextureImpl
|
||||
{
|
||||
public:
|
||||
|
@ -180,7 +188,8 @@ class TextureVk : public TextureImpl
|
|||
return mSampler.get();
|
||||
}
|
||||
|
||||
angle::Result ensureImageInitialized(ContextVk *contextVk);
|
||||
// Normally, initialize the image with enabled mipmap level counts.
|
||||
angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels);
|
||||
|
||||
Serial getSerial() const { return mSerial; }
|
||||
|
||||
|
@ -235,15 +244,6 @@ class TextureVk : public TextureImpl
|
|||
const gl::Rectangle &sourceArea,
|
||||
uint8_t **outDataPtr);
|
||||
|
||||
angle::Result copyImageDataToBuffer(ContextVk *contextVk,
|
||||
size_t sourceLevel,
|
||||
uint32_t layerCount,
|
||||
uint32_t baseLayer,
|
||||
const gl::Box &sourceArea,
|
||||
vk::BufferHelper **bufferOut,
|
||||
VkDeviceSize *bufferOffsetOut,
|
||||
uint8_t **outDataPtr);
|
||||
|
||||
angle::Result generateMipmapsWithCPU(const gl::Context *context);
|
||||
|
||||
angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk,
|
||||
|
@ -303,7 +303,14 @@ class TextureVk : public TextureImpl
|
|||
const uint32_t levelCount);
|
||||
void releaseImage(ContextVk *contextVk);
|
||||
void releaseStagingBuffer(ContextVk *contextVk);
|
||||
uint32_t getLevelCount() const;
|
||||
uint32_t getMipLevelCount(ImageMipLevels mipLevels) const;
|
||||
uint32_t getMaxLevelCount() const;
|
||||
angle::Result copyImageDataToStagingBuffer(ContextVk *contextVk,
|
||||
const gl::ImageDesc &desc,
|
||||
bool ignoreLayerCount,
|
||||
uint32_t currentLayer,
|
||||
uint32_t sourceLevel,
|
||||
uint32_t stagingDstMipLevel);
|
||||
angle::Result initImageViews(ContextVk *contextVk,
|
||||
const vk::Format &format,
|
||||
const bool sized,
|
||||
|
|
|
@ -2850,6 +2850,81 @@ bool ImageHelper::isUpdateStaged(uint32_t level, uint32_t layer)
|
|||
return false;
|
||||
}
|
||||
|
||||
angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
|
||||
size_t sourceLevel,
|
||||
uint32_t layerCount,
|
||||
uint32_t baseLayer,
|
||||
const gl::Box &sourceArea,
|
||||
vk::BufferHelper **bufferOut,
|
||||
VkDeviceSize *bufferOffsetOut,
|
||||
uint8_t **outDataPtr)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBuffer");
|
||||
|
||||
const angle::Format &imageFormat = mFormat->actualImageFormat();
|
||||
size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * sourceArea.depth *
|
||||
imageFormat.pixelBytes * layerCount;
|
||||
|
||||
vk::CommandBuffer *commandBuffer = nullptr;
|
||||
ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
|
||||
|
||||
// http://anglebug.com/3949: Need to handle DS combined aspect, will require copying D & S
|
||||
// separately. See ImageHelper::stageSubresourceUpdate for DS copy buff->image example.
|
||||
ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ||
|
||||
getAspectFlags() == VK_IMAGE_ASPECT_DEPTH_BIT ||
|
||||
getAspectFlags() == VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
// Transition the image to readable layout
|
||||
changeLayout(getAspectFlags(), vk::ImageLayout::TransferSrc, commandBuffer);
|
||||
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.image = mImage.getHandle();
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.subresourceRange.aspectMask = getAspectFlags();
|
||||
barrier.subresourceRange.baseArrayLayer = baseLayer;
|
||||
barrier.subresourceRange.layerCount = layerCount;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseMipLevel = static_cast<uint32_t>(sourceLevel);
|
||||
barrier.oldLayout = getCurrentLayout();
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
&barrier);
|
||||
|
||||
// Allocate staging buffer data
|
||||
ANGLE_TRY(allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr, bufferOut,
|
||||
bufferOffsetOut, nullptr));
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.bufferOffset = *bufferOffsetOut;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageExtent.width = sourceArea.width;
|
||||
region.imageExtent.height = sourceArea.height;
|
||||
region.imageExtent.depth = sourceArea.depth;
|
||||
region.imageOffset.x = sourceArea.x;
|
||||
region.imageOffset.y = sourceArea.y;
|
||||
region.imageOffset.z = sourceArea.z;
|
||||
region.imageSubresource.aspectMask = getAspectFlags();
|
||||
region.imageSubresource.baseArrayLayer = baseLayer;
|
||||
region.imageSubresource.layerCount = layerCount;
|
||||
region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
|
||||
|
||||
commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
|
||||
(*bufferOut)->getBuffer().getHandle(), 1, ®ion);
|
||||
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
&barrier);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
// ImageHelper::SubresourceUpdate implementation
|
||||
ImageHelper::SubresourceUpdate::SubresourceUpdate()
|
||||
: updateSource(UpdateSource::Buffer), buffer{VK_NULL_HANDLE}
|
||||
|
|
|
@ -882,6 +882,15 @@ class ImageHelper final : public CommandGraphResource
|
|||
uint32_t getBaseLevel();
|
||||
void setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
angle::Result copyImageDataToBuffer(ContextVk *contextVk,
|
||||
size_t sourceLevel,
|
||||
uint32_t layerCount,
|
||||
uint32_t baseLayer,
|
||||
const gl::Box &sourceArea,
|
||||
vk::BufferHelper **bufferOut,
|
||||
VkDeviceSize *bufferOffsetOut,
|
||||
uint8_t **outDataPtr);
|
||||
|
||||
private:
|
||||
void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
|
|
Загрузка…
Ссылка в новой задаче