Commit 26084d0a by Jamie Madill Committed by Commit Bot

Vulkan: Create TextureVk's Image lazily.

This defers the actual Image initialization until the Image is used as either a Framebuffer Attachment or OpenGL Texture object. This will allow us to construct an Image from multiple sub resources, like when we're initializing a mip chain, or a cube map texture. Also adds a helper "hasDepthOrStencilBits" function to angle::Format. Bug: angleproject:2318 Change-Id: Ife861560216581a90fc6da32a583f69886c7daea Reviewed-on: https://chromium-review.googlesource.com/985202Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 3418fe80
...@@ -219,6 +219,12 @@ bool TextureState::isCubeComplete() const ...@@ -219,6 +219,12 @@ bool TextureState::isCubeComplete() const
return true; return true;
} }
const ImageDesc &TextureState::getBaseLevelDesc() const
{
ASSERT(mType != TextureType::CubeMap || isCubeComplete());
return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
}
void TextureState::setCrop(const gl::Rectangle& rect) void TextureState::setCrop(const gl::Rectangle& rect)
{ {
mCropRect = rect; mCropRect = rect;
......
...@@ -115,6 +115,9 @@ struct TextureState final : private angle::NonCopyable ...@@ -115,6 +115,9 @@ struct TextureState final : private angle::NonCopyable
GLenum getUsage() const { return mUsage; } GLenum getUsage() const { return mUsage; }
GLenum getDepthStencilTextureMode() const { return mDepthStencilTextureMode; } GLenum getDepthStencilTextureMode() const { return mDepthStencilTextureMode; }
// Returns the desc of the base level. Only valid for cube-complete/mip-complete textures.
const ImageDesc &getBaseLevelDesc() const;
// GLES1 emulation: For GL_OES_draw_texture // GLES1 emulation: For GL_OES_draw_texture
void setCrop(const gl::Rectangle& rect); void setCrop(const gl::Rectangle& rect);
const gl::Rectangle& getCrop() const; const gl::Rectangle& getCrop() const;
......
...@@ -41,6 +41,8 @@ struct Format final : private angle::NonCopyable ...@@ -41,6 +41,8 @@ struct Format final : private angle::NonCopyable
static const Format &Get(ID id); static const Format &Get(ID id);
static ID InternalFormatToID(GLenum internalFormat); static ID InternalFormatToID(GLenum internalFormat);
constexpr bool hasDepthOrStencilBits() const;
ID id; ID id;
// The closest matching GL internal format for the storage this format uses. Note that this // The closest matching GL internal format for the storage this format uses. Note that this
...@@ -108,6 +110,10 @@ constexpr Format::Format(ID id, ...@@ -108,6 +110,10 @@ constexpr Format::Format(ID id,
{ {
} }
constexpr bool Format::hasDepthOrStencilBits() const
{
return depthBits > 0 || stencilBits > 0;
}
} // namespace angle } // namespace angle
#include "libANGLE/renderer/Format_ID_autogen.inl" #include "libANGLE/renderer/Format_ID_autogen.inl"
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h" #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx namespace rx
{ {
...@@ -142,7 +143,8 @@ void CommandGraphResource::onReadResource(CommandGraphNode *readingNode, Serial ...@@ -142,7 +143,8 @@ void CommandGraphResource::onReadResource(CommandGraphNode *readingNode, Serial
bool CommandGraphResource::checkResourceInUseAndRefreshDeps(RendererVk *renderer) bool CommandGraphResource::checkResourceInUseAndRefreshDeps(RendererVk *renderer)
{ {
if (!renderer->isResourceInUse(*this)) if (!renderer->isResourceInUse(*this) ||
(renderer->getCurrentQueueSerial() > mStoredQueueSerial))
{ {
mCurrentReadingNodes.clear(); mCurrentReadingNodes.clear();
mCurrentWritingNode = nullptr; mCurrentWritingNode = nullptr;
...@@ -243,6 +245,14 @@ void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer, ...@@ -243,6 +245,14 @@ void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
void CommandGraphNode::appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget) void CommandGraphNode::appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget)
{ {
ASSERT(mOutsideRenderPassCommands.valid());
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
colorRenderTarget->image->changeLayoutWithStages(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
&mOutsideRenderPassCommands);
mRenderPassDesc.packColorAttachment(*colorRenderTarget->image); mRenderPassDesc.packColorAttachment(*colorRenderTarget->image);
colorRenderTarget->resource->onWriteResource(this, serial); colorRenderTarget->resource->onWriteResource(this, serial);
} }
...@@ -250,6 +260,19 @@ void CommandGraphNode::appendColorRenderTarget(Serial serial, RenderTargetVk *co ...@@ -250,6 +260,19 @@ void CommandGraphNode::appendColorRenderTarget(Serial serial, RenderTargetVk *co
void CommandGraphNode::appendDepthStencilRenderTarget(Serial serial, void CommandGraphNode::appendDepthStencilRenderTarget(Serial serial,
RenderTargetVk *depthStencilRenderTarget) RenderTargetVk *depthStencilRenderTarget)
{ {
ASSERT(mOutsideRenderPassCommands.valid());
ASSERT(depthStencilRenderTarget->image->getFormat().textureFormat().hasDepthOrStencilBits());
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
const angle::Format &format = depthStencilRenderTarget->image->getFormat().textureFormat();
VkImageAspectFlags aspectFlags = (format.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) |
(format.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
depthStencilRenderTarget->image->changeLayoutWithStages(
aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
&mOutsideRenderPassCommands);
mRenderPassDesc.packDepthStencilAttachment(*depthStencilRenderTarget->image); mRenderPassDesc.packDepthStencilAttachment(*depthStencilRenderTarget->image);
depthStencilRenderTarget->resource->onWriteResource(this, serial); depthStencilRenderTarget->resource->onWriteResource(this, serial);
} }
......
...@@ -174,6 +174,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, ...@@ -174,6 +174,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
ASSERT(texture); ASSERT(texture);
TextureVk *textureVk = vk::GetImpl(texture); TextureVk *textureVk = vk::GetImpl(texture);
ANGLE_TRY(textureVk->ensureImageInitialized(mRenderer));
textureVk->onReadResource(graphNode, mRenderer->getCurrentQueueSerial()); textureVk->onReadResource(graphNode, mRenderer->getCurrentQueueSerial());
} }
} }
......
...@@ -568,11 +568,6 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -568,11 +568,6 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
colorRenderTarget->image->changeLayoutWithStages(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
commandBuffer);
(*nodeOut)->appendColorRenderTarget(currentSerial, colorRenderTarget); (*nodeOut)->appendColorRenderTarget(currentSerial, colorRenderTarget);
attachmentClearValues.emplace_back(contextVk->getClearColorValue()); attachmentClearValues.emplace_back(contextVk->getClearColorValue());
} }
...@@ -580,15 +575,6 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -580,15 +575,6 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil(); RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil();
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
const angle::Format &format = depthStencilRenderTarget->image->getFormat().textureFormat();
VkImageAspectFlags aspectFlags = (format.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) |
(format.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
depthStencilRenderTarget->image->changeLayoutWithStages(
aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
commandBuffer);
(*nodeOut)->appendDepthStencilRenderTarget(currentSerial, depthStencilRenderTarget); (*nodeOut)->appendDepthStencilRenderTarget(currentSerial, depthStencilRenderTarget);
attachmentClearValues.emplace_back(contextVk->getClearDepthStencilValue()); attachmentClearValues.emplace_back(contextVk->getClearDepthStencilValue());
} }
......
...@@ -25,19 +25,19 @@ void MapSwizzleState(GLenum internalFormat, ...@@ -25,19 +25,19 @@ void MapSwizzleState(GLenum internalFormat,
{ {
switch (internalFormat) switch (internalFormat)
{ {
case GL_LUMINANCE: case GL_LUMINANCE8_OES:
swizzleStateOut->swizzleRed = swizzleState.swizzleRed; swizzleStateOut->swizzleRed = swizzleState.swizzleRed;
swizzleStateOut->swizzleGreen = swizzleState.swizzleRed; swizzleStateOut->swizzleGreen = swizzleState.swizzleRed;
swizzleStateOut->swizzleBlue = swizzleState.swizzleRed; swizzleStateOut->swizzleBlue = swizzleState.swizzleRed;
swizzleStateOut->swizzleAlpha = GL_ONE; swizzleStateOut->swizzleAlpha = GL_ONE;
break; break;
case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8_OES:
swizzleStateOut->swizzleRed = swizzleState.swizzleRed; swizzleStateOut->swizzleRed = swizzleState.swizzleRed;
swizzleStateOut->swizzleGreen = swizzleState.swizzleRed; swizzleStateOut->swizzleGreen = swizzleState.swizzleRed;
swizzleStateOut->swizzleBlue = swizzleState.swizzleRed; swizzleStateOut->swizzleBlue = swizzleState.swizzleRed;
swizzleStateOut->swizzleAlpha = swizzleState.swizzleGreen; swizzleStateOut->swizzleAlpha = swizzleState.swizzleGreen;
break; break;
case GL_ALPHA: case GL_ALPHA8_OES:
swizzleStateOut->swizzleRed = GL_ZERO; swizzleStateOut->swizzleRed = GL_ZERO;
swizzleStateOut->swizzleGreen = GL_ZERO; swizzleStateOut->swizzleGreen = GL_ZERO;
swizzleStateOut->swizzleBlue = GL_ZERO; swizzleStateOut->swizzleBlue = GL_ZERO;
...@@ -48,8 +48,110 @@ void MapSwizzleState(GLenum internalFormat, ...@@ -48,8 +48,110 @@ void MapSwizzleState(GLenum internalFormat,
break; break;
} }
} }
constexpr VkBufferUsageFlags kStagingBufferFlags =
(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
constexpr size_t kStagingBufferSize = 1024 * 16;
} // anonymous namespace } // anonymous namespace
// StagingStorage implementation.
StagingStorage::StagingStorage()
: mStagingBuffer(kStagingBufferFlags, kStagingBufferSize), mCurrentBufferHandle(VK_NULL_HANDLE)
{
mStagingBuffer.init(1);
}
StagingStorage::~StagingStorage()
{
}
void StagingStorage::release(RendererVk *renderer)
{
mStagingBuffer.release(renderer);
}
gl::Error StagingStorage::stageSubresourceUpdate(ContextVk *contextVk,
const gl::Extents &extents,
const gl::InternalFormat &formatInfo,
const gl::PixelUnpackState &unpack,
GLenum type,
const uint8_t *pixels)
{
GLuint inputRowPitch = 0;
ANGLE_TRY_RESULT(
formatInfo.computeRowPitch(type, extents.width, unpack.alignment, unpack.rowLength),
inputRowPitch);
GLuint inputDepthPitch = 0;
ANGLE_TRY_RESULT(
formatInfo.computeDepthPitch(extents.height, unpack.imageHeight, inputRowPitch),
inputDepthPitch);
// TODO(jmadill): skip images for 3D Textures.
bool applySkipImages = false;
GLuint inputSkipBytes = 0;
ANGLE_TRY_RESULT(
formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages),
inputSkipBytes);
RendererVk *renderer = contextVk->getRenderer();
const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
const angle::Format &storageFormat = vkFormat.textureFormat();
size_t outputRowPitch = storageFormat.pixelBytes * extents.width;
size_t outputDepthPitch = outputRowPitch * extents.height;
uint8_t *stagingPointer = nullptr;
bool newBufferAllocated = false;
uint32_t stagingOffset = 0;
size_t allocationSize = outputDepthPitch * extents.depth;
mStagingBuffer.allocate(renderer, allocationSize, &stagingPointer, &mCurrentBufferHandle,
&stagingOffset, &newBufferAllocated);
const uint8_t *source = pixels + inputSkipBytes;
LoadImageFunctionInfo loadFunction = vkFormat.loadFunctions(type);
loadFunction.loadFunction(extents.width, extents.height, extents.depth, source, inputRowPitch,
inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
mCurrentCopyRegion.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
mCurrentCopyRegion.bufferRowLength = extents.width;
mCurrentCopyRegion.bufferImageHeight = extents.height;
mCurrentCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
mCurrentCopyRegion.imageSubresource.mipLevel = 0;
mCurrentCopyRegion.imageSubresource.baseArrayLayer = 0;
mCurrentCopyRegion.imageSubresource.layerCount = 1;
gl_vk::GetOffset(gl::Offset(), &mCurrentCopyRegion.imageOffset);
gl_vk::GetExtent(extents, &mCurrentCopyRegion.imageExtent);
return gl::NoError();
}
vk::Error StagingStorage::flushUpdatesToImage(RendererVk *renderer,
vk::ImageHelper *image,
vk::CommandBuffer *commandBuffer)
{
if (mCurrentBufferHandle != VK_NULL_HANDLE)
{
// Conservatively flush all writes to the image. We could use a more restricted barrier.
image->changeLayoutWithStages(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer);
ANGLE_TRY(mStagingBuffer.flush(renderer->getDevice()));
commandBuffer->copyBufferToImage(mCurrentBufferHandle, image->getImage(),
image->getCurrentLayout(), 1, &mCurrentCopyRegion);
mCurrentBufferHandle = VK_NULL_HANDLE;
}
return vk::NoError();
}
// TextureVk implementation.
TextureVk::TextureVk(const gl::TextureState &state) : TextureImpl(state) TextureVk::TextureVk(const gl::TextureState &state) : TextureImpl(state)
{ {
mRenderTarget.image = &mImage; mRenderTarget.image = &mImage;
...@@ -71,6 +173,8 @@ gl::Error TextureVk::onDestroy(const gl::Context *context) ...@@ -71,6 +173,8 @@ gl::Error TextureVk::onDestroy(const gl::Context *context)
renderer->releaseResource(*this, &mImageView); renderer->releaseResource(*this, &mImageView);
renderer->releaseResource(*this, &mSampler); renderer->releaseResource(*this, &mSampler);
mStagingStorage.release(renderer);
onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS); onStateChange(context, angle::SubjectMessage::DEPENDENT_DIRTY_BITS);
return gl::NoError(); return gl::NoError();
...@@ -109,39 +213,16 @@ gl::Error TextureVk::setImage(const gl::Context *context, ...@@ -109,39 +213,16 @@ gl::Error TextureVk::setImage(const gl::Context *context,
} }
// Early-out on empty textures, don't create a zero-sized storage. // Early-out on empty textures, don't create a zero-sized storage.
if (size.width == 0 || size.height == 0 || size.depth == 0) if (size.empty())
{ {
return gl::NoError(); return gl::NoError();
} }
// TODO(jmadill): support other types of textures. // TODO(jmadill): Cube map textures. http://anglebug.com/2318
ASSERT(target == gl::TextureTarget::_2D); if (target != gl::TextureTarget::_2D)
// Convert internalFormat to sized internal format.
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
if (!mImage.valid())
{ {
VkImageUsageFlags usage = UNIMPLEMENTED();
(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | return gl::InternalError();
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
ANGLE_TRY(mImage.init2D(device, size, vkFormat, 1, usage));
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage.initMemory(device, renderer->getMemoryProperties(), flags));
gl::SwizzleState mappedSwizzle;
MapSwizzleState(formatInfo.internalFormat, mState.getSwizzleState(), &mappedSwizzle);
ANGLE_TRY(
mImage.initImageView(device, VK_IMAGE_ASPECT_COLOR_BIT, mappedSwizzle, &mImageView));
// TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
VkClearColorValue black = {{0}};
mImage.clearColor(black, commandBuffer);
} }
if (!mSampler.valid()) if (!mSampler.valid())
...@@ -171,10 +252,16 @@ gl::Error TextureVk::setImage(const gl::Context *context, ...@@ -171,10 +252,16 @@ gl::Error TextureVk::setImage(const gl::Context *context,
ANGLE_TRY(mSampler.init(device, samplerInfo)); ANGLE_TRY(mSampler.init(device, samplerInfo));
} }
// Create a new graph node to store image initialization commands.
getNewWritingNode(renderer);
// Handle initial data. // Handle initial data.
if (pixels) if (pixels)
{ {
ANGLE_TRY(setSubImageImpl(contextVk, formatInfo, unpack, type, pixels)); // Convert internalFormat to sized internal format.
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
ANGLE_TRY(mStagingStorage.stageSubresourceUpdate(contextVk, size, formatInfo, unpack, type,
pixels));
} }
return gl::NoError(); return gl::NoError();
...@@ -191,71 +278,9 @@ gl::Error TextureVk::setSubImage(const gl::Context *context, ...@@ -191,71 +278,9 @@ gl::Error TextureVk::setSubImage(const gl::Context *context,
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
ANGLE_TRY(setSubImageImpl(contextVk, formatInfo, unpack, type, pixels)); ANGLE_TRY(mStagingStorage.stageSubresourceUpdate(
return gl::NoError(); contextVk, gl::Extents(area.width, area.height, area.depth), formatInfo, unpack, type,
} pixels));
gl::Error TextureVk::setSubImageImpl(ContextVk *contextVk,
const gl::InternalFormat &formatInfo,
const gl::PixelUnpackState &unpack,
GLenum type,
const uint8_t *pixels)
{
RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice();
const gl::Extents &size = mImage.getExtents();
const vk::Format &vkFormat = mImage.getFormat();
vk::ImageHelper stagingImage;
ANGLE_TRY(stagingImage.init2DStaging(device, renderer->getMemoryProperties(), vkFormat, size,
vk::StagingUsage::Write));
GLuint inputRowPitch = 0;
ANGLE_TRY_RESULT(
formatInfo.computeRowPitch(type, size.width, unpack.alignment, unpack.rowLength),
inputRowPitch);
GLuint inputDepthPitch = 0;
ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(size.height, unpack.imageHeight, inputRowPitch),
inputDepthPitch);
// TODO(jmadill): skip images for 3D Textures.
bool applySkipImages = false;
GLuint inputSkipBytes = 0;
ANGLE_TRY_RESULT(
formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages),
inputSkipBytes);
auto loadFunction = vkFormat.loadFunctions(type);
uint8_t *mapPointer = nullptr;
ANGLE_TRY(stagingImage.getDeviceMemory().map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
const uint8_t *source = pixels + inputSkipBytes;
// Get the subresource layout. This has important parameters like row pitch.
// TODO(jmadill): Fill out these parameters based on input parameters.
VkSubresourceLayout subresourceLayout;
stagingImage.getImage().getSubresourceLayout(device, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
&subresourceLayout);
loadFunction.loadFunction(size.width, size.height, size.depth, source, inputRowPitch,
inputDepthPitch, mapPointer,
static_cast<size_t>(subresourceLayout.rowPitch),
static_cast<size_t>(subresourceLayout.depthPitch));
stagingImage.getDeviceMemory().unmap(device);
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
vk::ImageHelper::Copy(&stagingImage, &mImage, gl::Offset(), gl::Offset(), size,
VK_IMAGE_ASPECT_COLOR_BIT, commandBuffer);
// Immediately release staging image.
// TODO(jmadill): Staging image re-use.
renderer->releaseObject(renderer->getCurrentQueueSerial(), &stagingImage);
return gl::NoError(); return gl::NoError();
} }
...@@ -363,12 +388,73 @@ gl::Error TextureVk::getAttachmentRenderTarget(const gl::Context *context, ...@@ -363,12 +388,73 @@ gl::Error TextureVk::getAttachmentRenderTarget(const gl::Context *context,
const gl::ImageIndex &imageIndex, const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
// TODO(jmadill): Handle cube textures. http://anglebug.com/2318
ASSERT(imageIndex.type == gl::TextureType::_2D); ASSERT(imageIndex.type == gl::TextureType::_2D);
// Non-zero mip level attachments are an ES 3.0 feature.
ASSERT(imageIndex.mipIndex == 0 && imageIndex.layerIndex == gl::ImageIndex::ENTIRE_LEVEL); ASSERT(imageIndex.mipIndex == 0 && imageIndex.layerIndex == gl::ImageIndex::ENTIRE_LEVEL);
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
ANGLE_TRY(ensureImageInitialized(renderer));
*rtOut = &mRenderTarget; *rtOut = &mRenderTarget;
return gl::NoError(); return gl::NoError();
} }
vk::Error TextureVk::ensureImageInitialized(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();
vk::CommandBuffer *commandBuffer = nullptr;
updateQueueSerial(renderer->getCurrentQueueSerial());
if (!hasChildlessWritingNode())
{
beginWriteResource(renderer, &commandBuffer);
}
else
{
vk::CommandGraphNode *node = getCurrentWritingNode();
commandBuffer = node->getOutsideRenderPassCommands();
if (!commandBuffer->valid())
{
ANGLE_TRY(node->beginOutsideRenderPassRecording(device, renderer->getCommandPool(),
&commandBuffer));
}
}
if (!mImage.valid())
{
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
const gl::Extents &extents = baseLevelDesc.size;
const vk::Format &format =
renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
VkImageUsageFlags usage =
(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
ANGLE_TRY(mImage.init2D(device, extents, format, 1, usage));
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage.initMemory(device, renderer->getMemoryProperties(), flags));
gl::SwizzleState mappedSwizzle;
MapSwizzleState(format.internalFormat, mState.getSwizzleState(), &mappedSwizzle);
ANGLE_TRY(
mImage.initImageView(device, VK_IMAGE_ASPECT_COLOR_BIT, mappedSwizzle, &mImageView));
// TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
VkClearColorValue black = {{0}};
mImage.clearColor(black, commandBuffer);
}
ANGLE_TRY(mStagingStorage.flushUpdatesToImage(renderer, &mImage, commandBuffer));
return vk::NoError();
}
void TextureVk::syncState(const gl::Texture::DirtyBits &dirtyBits) void TextureVk::syncState(const gl::Texture::DirtyBits &dirtyBits)
{ {
// TODO(jmadill): Texture sync state. // TODO(jmadill): Texture sync state.
......
...@@ -18,6 +18,31 @@ ...@@ -18,6 +18,31 @@
namespace rx namespace rx
{ {
class StagingStorage final : angle::NonCopyable
{
public:
StagingStorage();
~StagingStorage();
void release(RendererVk *renderer);
gl::Error stageSubresourceUpdate(ContextVk *contextVk,
const gl::Extents &extents,
const gl::InternalFormat &formatInfo,
const gl::PixelUnpackState &unpack,
GLenum type,
const uint8_t *pixels);
vk::Error flushUpdatesToImage(RendererVk *renderer,
vk::ImageHelper *image,
vk::CommandBuffer *commandBuffer);
private:
vk::DynamicBuffer mStagingBuffer;
VkBuffer mCurrentBufferHandle;
VkBufferImageCopy mCurrentCopyRegion;
};
class TextureVk : public TextureImpl, public vk::CommandGraphResource class TextureVk : public TextureImpl, public vk::CommandGraphResource
{ {
public: public:
...@@ -116,18 +141,16 @@ class TextureVk : public TextureImpl, public vk::CommandGraphResource ...@@ -116,18 +141,16 @@ class TextureVk : public TextureImpl, public vk::CommandGraphResource
const vk::ImageView &getImageView() const; const vk::ImageView &getImageView() const;
const vk::Sampler &getSampler() const; const vk::Sampler &getSampler() const;
private: vk::Error ensureImageInitialized(RendererVk *renderer);
gl::Error setSubImageImpl(ContextVk *contextVk,
const gl::InternalFormat &formatInfo,
const gl::PixelUnpackState &unpack,
GLenum type,
const uint8_t *pixels);
private:
vk::ImageHelper mImage; vk::ImageHelper mImage;
vk::ImageView mImageView; vk::ImageView mImageView;
vk::Sampler mSampler; vk::Sampler mSampler;
RenderTargetVk mRenderTarget; RenderTargetVk mRenderTarget;
StagingStorage mStagingStorage;
}; };
} // namespace rx } // namespace rx
......
...@@ -141,7 +141,6 @@ gl::Error VertexArrayVk::streamIndexData(RendererVk *renderer, ...@@ -141,7 +141,6 @@ gl::Error VertexArrayVk::streamIndexData(RendererVk *renderer,
ANGLE_TRY(mDynamicIndexData.flush(renderer->getDevice())); ANGLE_TRY(mDynamicIndexData.flush(renderer->getDevice()));
mCurrentElementArrayBufferOffset = offset; mCurrentElementArrayBufferOffset = offset;
return gl::NoError(); return gl::NoError();
} }
......
...@@ -429,6 +429,19 @@ void CommandBuffer::copyBuffer(const VkBuffer &srcBuffer, ...@@ -429,6 +429,19 @@ void CommandBuffer::copyBuffer(const VkBuffer &srcBuffer,
vkCmdCopyBuffer(mHandle, srcBuffer, destBuffer, regionCount, regions); vkCmdCopyBuffer(mHandle, srcBuffer, destBuffer, regionCount, regions);
} }
void CommandBuffer::copyBufferToImage(VkBuffer srcBuffer,
const Image &dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkBufferImageCopy *regions)
{
ASSERT(valid());
ASSERT(srcBuffer != VK_NULL_HANDLE);
ASSERT(dstImage.valid());
vkCmdCopyBufferToImage(mHandle, srcBuffer, dstImage.getHandle(), dstImageLayout, regionCount,
regions);
}
void CommandBuffer::clearColorImage(const vk::Image &image, void CommandBuffer::clearColorImage(const vk::Image &image,
VkImageLayout imageLayout, VkImageLayout imageLayout,
const VkClearColorValue &color, const VkClearColorValue &color,
...@@ -1251,8 +1264,21 @@ VkIndexType GetIndexType(GLenum elementType) ...@@ -1251,8 +1264,21 @@ VkIndexType GetIndexType(GLenum elementType)
return VK_INDEX_TYPE_MAX_ENUM; return VK_INDEX_TYPE_MAX_ENUM;
} }
} }
} // namespace gl_vk
void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset)
{
vkOffset->x = glOffset.x;
vkOffset->y = glOffset.y;
vkOffset->z = glOffset.z;
}
void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent)
{
vkExtent->width = glExtent.width;
vkExtent->height = glExtent.height;
vkExtent->depth = glExtent.depth;
}
} // namespace gl_vk
} // namespace rx } // namespace rx
std::ostream &operator<<(std::ostream &stream, const rx::vk::Error &error) std::ostream &operator<<(std::ostream &stream, const rx::vk::Error &error)
......
...@@ -356,6 +356,12 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -356,6 +356,12 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
uint32_t regionCount, uint32_t regionCount,
const VkBufferCopy *regions); const VkBufferCopy *regions);
void copyBufferToImage(VkBuffer srcBuffer,
const Image &dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkBufferImageCopy *regions);
void copyImage(const Image &srcImage, void copyImage(const Image &srcImage,
VkImageLayout srcImageLayout, VkImageLayout srcImageLayout,
const Image &dstImage, const Image &dstImage,
...@@ -651,6 +657,8 @@ VkFrontFace GetFrontFace(GLenum frontFace); ...@@ -651,6 +657,8 @@ VkFrontFace GetFrontFace(GLenum frontFace);
VkSampleCountFlagBits GetSamples(GLint sampleCount); VkSampleCountFlagBits GetSamples(GLint sampleCount);
VkComponentSwizzle GetSwizzle(const GLenum swizzle); VkComponentSwizzle GetSwizzle(const GLenum swizzle);
VkIndexType GetIndexType(GLenum elementType); VkIndexType GetIndexType(GLenum elementType);
void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
} // namespace gl_vk } // namespace gl_vk
} // namespace rx } // namespace rx
......
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