Commit 6722009e by Jamie Madill Committed by Commit Bot

Vulkan: Handle dirty RTs with state messages.

Prior to this CL we were handling dirty state change notifications by flushing the RT Images just prior to use or just after they were changed. This could lead to a few redundant checks in several places. It also meant we needed an owner pointer from the RT to the parent Image. This pointer would be null for Surfaces and Renderbuffers. This cleans up the image flushing logic to be handled by dirty bit notifications. When an app updates an attached Texture with TexSubImage or related calls it will send a notification to the Framebuffer. The Framebuffer then sets a dirty contents bit that is handled in the implementation. In Vulkan this means flushing the dirty bits. Requires adding a flag to the FramebufferImpl class to determine if we need to syncState before we checkStatus. Adding the option allows us to only call syncState for the GL back-end. Not calling syncState allows the robust resource init operation to happen *before* we syncState. Which in turn allows FramebuffeVk to initialize the VkImages in one go. Added new regression tests for Texture updates. This might not cover all cases. I found it was very hard to trigger some of the resource update staging in TextureVk. Bug: angleproject:3427 Change-Id: Idfa177436ba7fcb9d398f2b67922e085f778f82a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1601552 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 3f3a05d4
...@@ -467,7 +467,9 @@ void Context::initialize() ...@@ -467,7 +467,9 @@ void Context::initialize()
mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK);
mClearDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING); mClearDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
mClearDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
// We sync the draw Framebuffer manually in prepareForClear to allow the clear calls to do
// more custom handling for robust resource init.
mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED); mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED);
mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR); mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR);
...@@ -3498,17 +3500,21 @@ bool Context::noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei insta ...@@ -3498,17 +3500,21 @@ bool Context::noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei insta
angle::Result Context::prepareForClear(GLbitfield mask) angle::Result Context::prepareForClear(GLbitfield mask)
{ {
ANGLE_TRY(syncDirtyObjects(mClearDirtyObjects)); // Sync the draw framebuffer manually after the clear attachments.
ASSERT(mClearDirtyObjects.none());
ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearAttachmentsInitialized(this, mask)); ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearAttachmentsInitialized(this, mask));
ANGLE_TRY(mState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER));
ANGLE_TRY(syncDirtyBits(mClearDirtyBits)); ANGLE_TRY(syncDirtyBits(mClearDirtyBits));
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result Context::prepareForClearBuffer(GLenum buffer, GLint drawbuffer) angle::Result Context::prepareForClearBuffer(GLenum buffer, GLint drawbuffer)
{ {
ANGLE_TRY(syncDirtyObjects(mClearDirtyObjects)); // Sync the draw framebuffer manually after the clear attachments.
ASSERT(mClearDirtyObjects.none());
ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearBufferAttachmentsInitialized(this, buffer, ANGLE_TRY(mState.getDrawFramebuffer()->ensureClearBufferAttachmentsInitialized(this, buffer,
drawbuffer)); drawbuffer));
ANGLE_TRY(mState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER));
ANGLE_TRY(syncDirtyBits(mClearDirtyBits)); ANGLE_TRY(syncDirtyBits(mClearDirtyBits));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -8190,8 +8196,11 @@ void Context::onSubjectStateChange(const Context *context, ...@@ -8190,8 +8196,11 @@ void Context::onSubjectStateChange(const Context *context,
default: default:
if (index < kTextureMaxSubjectIndex) if (index < kTextureMaxSubjectIndex)
{ {
mState.onActiveTextureStateChange(this, index); if (message != angle::SubjectMessage::ContentsChanged)
mStateCache.onActiveTextureChange(this); {
mState.onActiveTextureStateChange(this, index);
mStateCache.onActiveTextureChange(this);
}
} }
else if (index < kUniformBufferMaxSubjectIndex) else if (index < kUniformBufferMaxSubjectIndex)
{ {
......
...@@ -968,11 +968,16 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -968,11 +968,16 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE) if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
{ {
angle::Result err = syncState(context); // We can skip syncState on several back-ends.
if (err != angle::Result::Continue) if (mImpl->shouldSyncStateBeforeCheckStatus())
{ {
return 0; angle::Result err = syncState(context);
if (err != angle::Result::Continue)
{
return 0;
}
} }
if (!mImpl->checkStatus(context)) if (!mImpl->checkStatus(context))
{ {
mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED; mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
...@@ -1848,6 +1853,14 @@ void Framebuffer::onSubjectStateChange(const Context *context, ...@@ -1848,6 +1853,14 @@ void Framebuffer::onSubjectStateChange(const Context *context,
{ {
if (message != angle::SubjectMessage::SubjectChanged) if (message != angle::SubjectMessage::SubjectChanged)
{ {
// This can be triggered by SubImage calls for Textures.
if (message == angle::SubjectMessage::ContentsChanged)
{
mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + index);
onStateChange(context, angle::SubjectMessage::DirtyBitsFlagged);
return;
}
// This can be triggered by the GL back-end TextureGL class. // This can be triggered by the GL back-end TextureGL class.
ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged); ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged);
return; return;
......
...@@ -314,6 +314,11 @@ class Framebuffer final : public angle::ObserverInterface, ...@@ -314,6 +314,11 @@ class Framebuffer final : public angle::ObserverInterface,
DIRTY_BIT_COLOR_ATTACHMENT_0 + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS, DIRTY_BIT_COLOR_ATTACHMENT_0 + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS,
DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX, DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX,
DIRTY_BIT_STENCIL_ATTACHMENT, DIRTY_BIT_STENCIL_ATTACHMENT,
DIRTY_BIT_COLOR_BUFFER_CONTENTS_0,
DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX =
DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS,
DIRTY_BIT_DEPTH_BUFFER_CONTENTS,
DIRTY_BIT_STENCIL_BUFFER_CONTENTS,
DIRTY_BIT_DRAW_BUFFERS, DIRTY_BIT_DRAW_BUFFERS,
DIRTY_BIT_READ_BUFFER, DIRTY_BIT_READ_BUFFER,
DIRTY_BIT_DEFAULT_WIDTH, DIRTY_BIT_DEFAULT_WIDTH,
......
...@@ -1058,6 +1058,8 @@ angle::Result Texture::setSubImage(Context *context, ...@@ -1058,6 +1058,8 @@ angle::Result Texture::setSubImage(Context *context,
ANGLE_TRY(handleMipmapGenerationHint(context, level)); ANGLE_TRY(handleMipmapGenerationHint(context, level));
onStateChange(context, angle::SubjectMessage::ContentsChanged);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1103,8 +1105,12 @@ angle::Result Texture::setCompressedSubImage(const Context *context, ...@@ -1103,8 +1105,12 @@ angle::Result Texture::setCompressedSubImage(const Context *context,
ImageIndex index = ImageIndex::MakeFromTarget(target, level); ImageIndex index = ImageIndex::MakeFromTarget(target, level);
return mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize, ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
pixels); pixels));
onStateChange(context, angle::SubjectMessage::ContentsChanged);
return angle::Result::Continue;
} }
angle::Result Texture::copyImage(Context *context, angle::Result Texture::copyImage(Context *context,
...@@ -1158,6 +1164,8 @@ angle::Result Texture::copySubImage(Context *context, ...@@ -1158,6 +1164,8 @@ angle::Result Texture::copySubImage(Context *context,
ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source)); ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex())); ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
onStateChange(context, angle::SubjectMessage::ContentsChanged);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1222,8 +1230,13 @@ angle::Result Texture::copySubTexture(const Context *context, ...@@ -1222,8 +1230,13 @@ angle::Result Texture::copySubTexture(const Context *context,
ImageIndex index = ImageIndex::MakeFromTarget(target, level); ImageIndex index = ImageIndex::MakeFromTarget(target, level);
return mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox, unpackFlipY, ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source); unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
source));
onStateChange(context, angle::SubjectMessage::ContentsChanged);
return angle::Result::Continue;
} }
angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source) angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
......
...@@ -86,11 +86,23 @@ class FramebufferImpl : angle::NonCopyable ...@@ -86,11 +86,23 @@ class FramebufferImpl : angle::NonCopyable
size_t index, size_t index,
GLfloat *xy) const = 0; GLfloat *xy) const = 0;
// Special configuration option for checkStatus(). Some back-ends don't require a syncState
// before calling checkStatus. In practice the GL back-end is the only config that needs
// syncState because it depends on the behaviour of the driver. Allowing the Vulkan and
// D3D back-ends to skip syncState lets us do more work in the syncState call.
virtual bool shouldSyncStateBeforeCheckStatus() const;
const gl::FramebufferState &getState() const { return mState; } const gl::FramebufferState &getState() const { return mState; }
protected: protected:
const gl::FramebufferState &mState; const gl::FramebufferState &mState;
}; };
inline bool FramebufferImpl::shouldSyncStateBeforeCheckStatus() const
{
return false;
}
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ #endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_
...@@ -86,11 +86,13 @@ angle::Result RenderTargetCache<RenderTargetT>::update(const gl::Context *contex ...@@ -86,11 +86,13 @@ angle::Result RenderTargetCache<RenderTargetT>::update(const gl::Context *contex
break; break;
default: default:
{ {
ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
size_t colorIndex = {
static_cast<size_t>(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); size_t colorIndex = static_cast<size_t>(
ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex)); dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex));
}
break; break;
} }
} }
......
...@@ -602,6 +602,11 @@ angle::Result FramebufferGL::getSamplePosition(const gl::Context *context, ...@@ -602,6 +602,11 @@ angle::Result FramebufferGL::getSamplePosition(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
bool FramebufferGL::shouldSyncStateBeforeCheckStatus() const
{
return true;
}
bool FramebufferGL::checkStatus(const gl::Context *context) const bool FramebufferGL::checkStatus(const gl::Context *context) const
{ {
const FunctionsGL *functions = GetFunctionsGL(context); const FunctionsGL *functions = GetFunctionsGL(context);
...@@ -691,16 +696,19 @@ angle::Result FramebufferGL::syncState(const gl::Context *context, ...@@ -691,16 +696,19 @@ angle::Result FramebufferGL::syncState(const gl::Context *context,
break; break;
default: default:
{ {
ASSERT(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && static_assert(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); if (dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
size_t index =
static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
const FramebufferAttachment *newAttachment = mState.getColorAttachment(index);
BindFramebufferAttachment(
functions, static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index), newAttachment);
if (newAttachment)
{ {
attachment = newAttachment; size_t index =
static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
const FramebufferAttachment *newAttachment = mState.getColorAttachment(index);
BindFramebufferAttachment(functions,
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
newAttachment);
if (newAttachment)
{
attachment = newAttachment;
}
} }
break; break;
} }
......
...@@ -78,6 +78,9 @@ class FramebufferGL : public FramebufferImpl ...@@ -78,6 +78,9 @@ class FramebufferGL : public FramebufferImpl
size_t index, size_t index,
GLfloat *xy) const override; GLfloat *xy) const override;
// The GL back-end requires a full sync state before we call checkStatus.
bool shouldSyncStateBeforeCheckStatus() const override;
bool checkStatus(const gl::Context *context) const override; bool checkStatus(const gl::Context *context) const override;
angle::Result syncState(const gl::Context *context, angle::Result syncState(const gl::Context *context,
......
...@@ -810,6 +810,35 @@ bool FramebufferVk::checkStatus(const gl::Context *context) const ...@@ -810,6 +810,35 @@ bool FramebufferVk::checkStatus(const gl::Context *context) const
return true; return true;
} }
angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context, size_t colorIndexGL)
{
ContextVk *contextVk = vk::GetImpl(context);
ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
// Update cached masks for masked clears.
RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
if (renderTarget)
{
const angle::Format &emulatedFormat = renderTarget->getImageFormat().imageFormat();
updateActiveColorMasks(colorIndexGL, emulatedFormat.redBits > 0,
emulatedFormat.greenBits > 0, emulatedFormat.blueBits > 0,
emulatedFormat.alphaBits > 0);
const angle::Format &sourceFormat = renderTarget->getImageFormat().angleFormat();
mEmulatedAlphaAttachmentMask.set(
colorIndexGL, sourceFormat.alphaBits == 0 && emulatedFormat.alphaBits > 0);
contextVk->updateColorMask(context->getState().getBlendState());
}
else
{
updateActiveColorMasks(colorIndexGL, false, false, false, false);
}
return angle::Result::Continue;
}
angle::Result FramebufferVk::syncState(const gl::Context *context, angle::Result FramebufferVk::syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) const gl::Framebuffer::DirtyBits &dirtyBits)
{ {
...@@ -825,6 +854,10 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -825,6 +854,10 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState)); ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
break; break;
case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
ANGLE_TRY(mRenderTargetCache.getDepthStencil()->flushStagedUpdates(contextVk));
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
...@@ -834,33 +867,21 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -834,33 +867,21 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
break; break;
default: default:
{ {
ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
size_t colorIndexGL =
static_cast<size_t>(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
ANGLE_TRY(
mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
// Update cached masks for masked clears.
RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
if (renderTarget)
{ {
const angle::Format &emulatedFormat = size_t colorIndexGL = static_cast<size_t>(
renderTarget->getImageFormat().imageFormat(); dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
updateActiveColorMasks( ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
colorIndexGL, emulatedFormat.redBits > 0, emulatedFormat.greenBits > 0,
emulatedFormat.blueBits > 0, emulatedFormat.alphaBits > 0);
const angle::Format &sourceFormat =
renderTarget->getImageFormat().angleFormat();
mEmulatedAlphaAttachmentMask.set(
colorIndexGL, sourceFormat.alphaBits == 0 && emulatedFormat.alphaBits > 0);
contextVk->updateColorMask(context->getState().getBlendState());
} }
else else
{ {
updateActiveColorMasks(colorIndexGL, false, false, false, false); ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
size_t colorIndexGL = static_cast<size_t>(
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
ANGLE_TRY(mRenderTargetCache.getColors()[colorIndexGL]->flushStagedUpdates(
contextVk));
} }
break; break;
} }
...@@ -1171,13 +1192,10 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1171,13 +1192,10 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
ANGLE_TRY(renderTarget->ensureImageInitialized(contextVk));
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
// Note that although we're reading from the image, we need to update the layout below. // Note that although we're reading from the image, we need to update the layout below.
vk::ImageHelper *srcImage = vk::ImageHelper *srcImage =
renderTarget->getImageForRead(&mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer); renderTarget->getImageForRead(&mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer);
......
...@@ -186,6 +186,7 @@ class FramebufferVk : public FramebufferImpl ...@@ -186,6 +186,7 @@ class FramebufferVk : public FramebufferImpl
uint8_t clearStencilValue); uint8_t clearStencilValue);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a); void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
void updateRenderPassDesc(); void updateRenderPassDesc();
angle::Result updateColorAttachment(const gl::Context *context, size_t colorIndex);
WindowSurfaceVk *mBackbuffer; WindowSurfaceVk *mBackbuffer;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h" #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h" #include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h" #include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
...@@ -17,7 +18,7 @@ ...@@ -17,7 +18,7 @@
namespace rx namespace rx
{ {
RenderTargetVk::RenderTargetVk() RenderTargetVk::RenderTargetVk()
: mImage(nullptr), mImageView(nullptr), mLevelIndex(0), mLayerIndex(0), mOwner(nullptr) : mImage(nullptr), mImageView(nullptr), mLevelIndex(0), mLayerIndex(0)
{} {}
RenderTargetVk::~RenderTargetVk() {} RenderTargetVk::~RenderTargetVk() {}
...@@ -26,21 +27,18 @@ RenderTargetVk::RenderTargetVk(RenderTargetVk &&other) ...@@ -26,21 +27,18 @@ RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
: mImage(other.mImage), : mImage(other.mImage),
mImageView(other.mImageView), mImageView(other.mImageView),
mLevelIndex(other.mLevelIndex), mLevelIndex(other.mLevelIndex),
mLayerIndex(other.mLayerIndex), mLayerIndex(other.mLayerIndex)
mOwner(other.mOwner)
{} {}
void RenderTargetVk::init(vk::ImageHelper *image, void RenderTargetVk::init(vk::ImageHelper *image,
vk::ImageView *imageView, vk::ImageView *imageView,
size_t levelIndex, size_t levelIndex,
size_t layerIndex, size_t layerIndex)
TextureVk *owner)
{ {
mImage = image; mImage = image;
mImageView = imageView; mImageView = imageView;
mLevelIndex = levelIndex; mLevelIndex = levelIndex;
mLayerIndex = layerIndex; mLayerIndex = layerIndex;
mOwner = owner;
} }
void RenderTargetVk::reset() void RenderTargetVk::reset()
...@@ -49,7 +47,6 @@ void RenderTargetVk::reset() ...@@ -49,7 +47,6 @@ void RenderTargetVk::reset()
mImageView = nullptr; mImageView = nullptr;
mLevelIndex = 0; mLevelIndex = 0;
mLayerIndex = 0; mLayerIndex = 0;
mOwner = nullptr;
} }
angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk, angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk,
...@@ -59,8 +56,6 @@ angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk, ...@@ -59,8 +56,6 @@ angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk,
ASSERT(commandBuffer->valid()); ASSERT(commandBuffer->valid());
ASSERT(!mImage->getFormat().imageFormat().hasDepthOrStencilBits()); ASSERT(!mImage->getFormat().imageFormat().hasDepthOrStencilBits());
ANGLE_TRY(ensureImageInitialized(contextVk));
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361 // TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment, mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
commandBuffer); commandBuffer);
...@@ -82,8 +77,6 @@ angle::Result RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, ...@@ -82,8 +77,6 @@ angle::Result RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk,
const angle::Format &format = mImage->getFormat().imageFormat(); const angle::Format &format = mImage->getFormat().imageFormat();
VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format);
ANGLE_TRY(ensureImageInitialized(contextVk));
mImage->changeLayout(aspectFlags, vk::ImageLayout::DepthStencilAttachment, commandBuffer); mImage->changeLayout(aspectFlags, vk::ImageLayout::DepthStencilAttachment, commandBuffer);
// Set up dependencies between the RT resource and the Framebuffer. // Set up dependencies between the RT resource and the Framebuffer.
...@@ -132,7 +125,6 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, vk::ImageView ...@@ -132,7 +125,6 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, vk::ImageView
ASSERT(image && image->valid() && imageView && imageView->valid()); ASSERT(image && image->valid() && imageView && imageView->valid());
mImage = image; mImage = image;
mImageView = imageView; mImageView = imageView;
mOwner = nullptr;
} }
vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource, vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource,
...@@ -170,16 +162,16 @@ vk::ImageHelper *RenderTargetVk::getImageForWrite(vk::CommandGraphResource *writ ...@@ -170,16 +162,16 @@ vk::ImageHelper *RenderTargetVk::getImageForWrite(vk::CommandGraphResource *writ
return mImage; return mImage;
} }
angle::Result RenderTargetVk::ensureImageInitialized(ContextVk *contextVk) angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk)
{ {
if (mOwner) ASSERT(mImage->valid());
{ if (!mImage->hasStagedUpdates())
// If the render target source is a texture, make sure the image is initialized and its return angle::Result::Continue;
// staged updates flushed.
return mOwner->ensureImageInitialized(contextVk); vk::CommandBuffer *commandBuffer;
} ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
return mImage->flushStagedUpdates(contextVk, mLevelIndex, mLevelIndex + 1, mLayerIndex,
return angle::Result::Continue; mLayerIndex + 1, commandBuffer);
} }
} // namespace rx } // namespace rx
...@@ -46,8 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -46,8 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void init(vk::ImageHelper *image, void init(vk::ImageHelper *image,
vk::ImageView *imageView, vk::ImageView *imageView,
size_t levelIndex, size_t levelIndex,
size_t layerIndex, size_t layerIndex);
TextureVk *owner);
void reset(); void reset();
// Note: RenderTargets should be called in order, with the depth/stencil onRender last. // Note: RenderTargets should be called in order, with the depth/stencil onRender last.
...@@ -79,7 +78,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -79,7 +78,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// RenderTargetVk pointer. // RenderTargetVk pointer.
void updateSwapchainImage(vk::ImageHelper *image, vk::ImageView *imageView); void updateSwapchainImage(vk::ImageHelper *image, vk::ImageView *imageView);
angle::Result ensureImageInitialized(ContextVk *contextVk); angle::Result flushStagedUpdates(ContextVk *contextVk);
private: private:
vk::ImageHelper *mImage; vk::ImageHelper *mImage;
...@@ -88,10 +87,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -88,10 +87,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
vk::ImageView *mImageView; vk::ImageView *mImageView;
size_t mLevelIndex; size_t mLevelIndex;
size_t mLayerIndex; size_t mLayerIndex;
// If owned by the texture, this will be non-nullptr, and is used to ensure texture changes
// are flushed.
TextureVk *mOwner;
}; };
} // namespace rx } // namespace rx
......
...@@ -85,10 +85,9 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context, ...@@ -85,10 +85,9 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
&mImageView, 0, 1)); &mImageView, 0, 1));
// Clear the renderbuffer if it has emulated channels. // Clear the renderbuffer if it has emulated channels.
ANGLE_TRY(mImage->clearIfEmulatedFormat(vk::GetImpl(context), gl::ImageIndex::Make2D(0), mImage->clearIfEmulatedFormat(vk::GetImpl(context), gl::ImageIndex::Make2D(0), vkFormat);
vkFormat));
mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr); mRenderTarget.init(mImage, &mImageView, 0, 0);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -135,8 +134,7 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex ...@@ -135,8 +134,7 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
gl::SwizzleState(), &mImageView, imageVk->getImageLevel(), gl::SwizzleState(), &mImageView, imageVk->getImageLevel(),
1, imageVk->getImageLayer(), 1)); 1, imageVk->getImageLayer(), 1));
mRenderTarget.init(mImage, &mImageView, imageVk->getImageLevel(), imageVk->getImageLayer(), mRenderTarget.init(mImage, &mImageView, imageVk->getImageLevel(), imageVk->getImageLayer());
nullptr);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -147,6 +145,7 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte ...@@ -147,6 +145,7 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
ASSERT(mImage && mImage->valid()); ASSERT(mImage && mImage->valid());
ANGLE_TRY(mRenderTarget.flushStagedUpdates(vk::GetImpl(context)));
*rtOut = &mRenderTarget; *rtOut = &mRenderTarget;
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -87,11 +87,34 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags = ...@@ -87,11 +87,34 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags =
} // namespace } // namespace
OffscreenSurfaceVk::AttachmentImage::AttachmentImage() SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
SurfaceVk::~SurfaceVk() = default;
angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut)
{ {
renderTarget.init(&image, &imageView, 0, 0, nullptr); ContextVk *contextVk = vk::GetImpl(context);
if (binding == GL_BACK)
{
ANGLE_TRY(mColorRenderTarget.flushStagedUpdates(contextVk));
*rtOut = &mColorRenderTarget;
}
else
{
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
ANGLE_TRY(mDepthStencilRenderTarget.flushStagedUpdates(contextVk));
*rtOut = &mDepthStencilRenderTarget;
}
return angle::Result::Continue;
} }
OffscreenSurfaceVk::AttachmentImage::AttachmentImage() {}
OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default; OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *displayVk, angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *displayVk,
...@@ -120,7 +143,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display ...@@ -120,7 +143,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
&imageView, 0, 1)); &imageView, 0, 1));
// Clear the image if it has emulated channels. // Clear the image if it has emulated channels.
ANGLE_TRY(image.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), vkFormat)); image.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), vkFormat);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -138,8 +161,12 @@ void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display) ...@@ -138,8 +161,12 @@ void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState,
EGLint width, EGLint width,
EGLint height) EGLint height)
: SurfaceImpl(surfaceState), mWidth(width), mHeight(height) : SurfaceVk(surfaceState), mWidth(width), mHeight(height)
{} {
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageView, 0, 0);
mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
&mDepthStencilAttachment.imageView, 0, 0);
}
OffscreenSurfaceVk::~OffscreenSurfaceVk() {} OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
...@@ -250,25 +277,6 @@ EGLint OffscreenSurfaceVk::getSwapBehavior() const ...@@ -250,25 +277,6 @@ EGLint OffscreenSurfaceVk::getSwapBehavior() const
return EGL_BUFFER_DESTROYED; return EGL_BUFFER_DESTROYED;
} }
angle::Result OffscreenSurfaceVk::getAttachmentRenderTarget(
const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut)
{
if (binding == GL_BACK)
{
*rtOut = &mColorAttachment.renderTarget;
}
else
{
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
*rtOut = &mDepthStencilAttachment.renderTarget;
}
return angle::Result::Continue;
}
angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context, angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
...@@ -351,7 +359,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, ...@@ -351,7 +359,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window, EGLNativeWindowType window,
EGLint width, EGLint width,
EGLint height) EGLint height)
: SurfaceImpl(surfaceState), : SurfaceVk(surfaceState),
mNativeWindowType(window), mNativeWindowType(window),
mSurface(VK_NULL_HANDLE), mSurface(VK_NULL_HANDLE),
mInstance(VK_NULL_HANDLE), mInstance(VK_NULL_HANDLE),
...@@ -364,10 +372,10 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, ...@@ -364,10 +372,10 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
mCurrentSwapchainImageIndex(0), mCurrentSwapchainImageIndex(0),
mCurrentSwapHistoryIndex(0) mCurrentSwapHistoryIndex(0)
{ {
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0, nullptr);
// Initialize the color render target with the multisampled targets. If not multisampled, the // Initialize the color render target with the multisampled targets. If not multisampled, the
// render target will be updated to refer to a swapchain image on every acquire. // render target will be updated to refer to a swapchain image on every acquire.
mColorRenderTarget.init(&mColorImageMS, &mColorImageViewMS, 0, 0, nullptr); mColorRenderTarget.init(&mColorImageMS, &mColorImageViewMS, 0, 0);
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0);
} }
WindowSurfaceVk::~WindowSurfaceVk() WindowSurfaceVk::~WindowSurfaceVk()
...@@ -604,8 +612,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -604,8 +612,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
&mColorImageViewMS, 0, 1)); &mColorImageViewMS, 0, 1));
// Clear the image if it has emulated channels. // Clear the image if it has emulated channels.
ANGLE_TRY( mColorImageMS.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), format);
mColorImageMS.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), format));
} }
mSwapchainImages.resize(imageCount); mSwapchainImages.resize(imageCount);
...@@ -627,8 +634,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -627,8 +634,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
// Clear the image if it has emulated channels. If a multisampled image exists, this // Clear the image if it has emulated channels. If a multisampled image exists, this
// image will be unused until a pre-present resolve, at which point it will be fully // image will be unused until a pre-present resolve, at which point it will be fully
// initialized and wouldn't need a clear. // initialized and wouldn't need a clear.
ANGLE_TRY( member.image.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), format);
member.image.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), format));
} }
} }
...@@ -652,8 +658,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -652,8 +658,7 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
// We will need to pass depth/stencil image views to the RenderTargetVk in the future. // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
// Clear the image if it has emulated channels. // Clear the image if it has emulated channels.
ANGLE_TRY(mDepthStencilImage.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), mDepthStencilImage.clearIfEmulatedFormat(displayVk, gl::ImageIndex::Make2D(0), dsFormat);
dsFormat));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -880,7 +885,7 @@ angle::Result WindowSurfaceVk::present(DisplayVk *displayVk, ...@@ -880,7 +885,7 @@ angle::Result WindowSurfaceVk::present(DisplayVk *displayVk,
// Update the swap history for this presentation // Update the swap history for this presentation
swap.sharedFence = renderer->getLastSubmittedFence(); swap.sharedFence = renderer->getLastSubmittedFence();
swap.semaphores = std::move(mFlushSemaphoreChain); swap.semaphores = std::move(mFlushSemaphoreChain);
++mCurrentSwapHistoryIndex; ++mCurrentSwapHistoryIndex;
mCurrentSwapHistoryIndex = mCurrentSwapHistoryIndex =
mCurrentSwapHistoryIndex == mSwapHistory.size() ? 0 : mCurrentSwapHistoryIndex; mCurrentSwapHistoryIndex == mSwapHistory.size() ? 0 : mCurrentSwapHistoryIndex;
...@@ -1053,24 +1058,6 @@ EGLint WindowSurfaceVk::getSwapBehavior() const ...@@ -1053,24 +1058,6 @@ EGLint WindowSurfaceVk::getSwapBehavior() const
return EGL_BUFFER_DESTROYED; return EGL_BUFFER_DESTROYED;
} }
angle::Result WindowSurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut)
{
if (binding == GL_BACK)
{
*rtOut = &mColorRenderTarget;
}
else
{
ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
*rtOut = &mDepthStencilRenderTarget;
}
return angle::Result::Continue;
}
angle::Result WindowSurfaceVk::getCurrentFramebuffer(vk::Context *context, angle::Result WindowSurfaceVk::getCurrentFramebuffer(vk::Context *context,
const vk::RenderPass &compatibleRenderPass, const vk::RenderPass &compatibleRenderPass,
vk::Framebuffer **framebufferOut) vk::Framebuffer **framebufferOut)
......
...@@ -20,7 +20,23 @@ namespace rx ...@@ -20,7 +20,23 @@ namespace rx
{ {
class RendererVk; class RendererVk;
class OffscreenSurfaceVk : public SurfaceImpl class SurfaceVk : public SurfaceImpl
{
public:
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut) override;
protected:
SurfaceVk(const egl::SurfaceState &surfaceState);
~SurfaceVk() override;
RenderTargetVk mColorRenderTarget;
RenderTargetVk mDepthStencilRenderTarget;
};
class OffscreenSurfaceVk : public SurfaceVk
{ {
public: public:
OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, EGLint width, EGLint height); OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, EGLint width, EGLint height);
...@@ -52,11 +68,6 @@ class OffscreenSurfaceVk : public SurfaceImpl ...@@ -52,11 +68,6 @@ class OffscreenSurfaceVk : public SurfaceImpl
EGLint isPostSubBufferSupported() const override; EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut) override;
angle::Result initializeContents(const gl::Context *context, angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override; const gl::ImageIndex &imageIndex) override;
...@@ -77,7 +88,6 @@ class OffscreenSurfaceVk : public SurfaceImpl ...@@ -77,7 +88,6 @@ class OffscreenSurfaceVk : public SurfaceImpl
vk::ImageHelper image; vk::ImageHelper image;
vk::ImageView imageView; vk::ImageView imageView;
RenderTargetVk renderTarget;
}; };
angle::Result initializeImpl(DisplayVk *displayVk); angle::Result initializeImpl(DisplayVk *displayVk);
...@@ -89,7 +99,7 @@ class OffscreenSurfaceVk : public SurfaceImpl ...@@ -89,7 +99,7 @@ class OffscreenSurfaceVk : public SurfaceImpl
AttachmentImage mDepthStencilAttachment; AttachmentImage mDepthStencilAttachment;
}; };
class WindowSurfaceVk : public SurfaceImpl class WindowSurfaceVk : public SurfaceVk
{ {
public: public:
WindowSurfaceVk(const egl::SurfaceState &surfaceState, WindowSurfaceVk(const egl::SurfaceState &surfaceState,
...@@ -125,11 +135,6 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -125,11 +135,6 @@ class WindowSurfaceVk : public SurfaceImpl
EGLint isPostSubBufferSupported() const override; EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
FramebufferAttachmentRenderTarget **rtOut) override;
angle::Result initializeContents(const gl::Context *context, angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override; const gl::ImageIndex &imageIndex) override;
...@@ -147,7 +152,7 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -147,7 +152,7 @@ class WindowSurfaceVk : public SurfaceImpl
VkInstance mInstance; VkInstance mInstance;
private: private:
virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) = 0; virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) = 0;
virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0; virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0;
angle::Result initializeImpl(DisplayVk *displayVk); angle::Result initializeImpl(DisplayVk *displayVk);
...@@ -178,9 +183,6 @@ class WindowSurfaceVk : public SurfaceImpl ...@@ -178,9 +183,6 @@ class WindowSurfaceVk : public SurfaceImpl
VkSurfaceTransformFlagBitsKHR mPreTransform; VkSurfaceTransformFlagBitsKHR mPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha; VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
RenderTargetVk mColorRenderTarget;
RenderTargetVk mDepthStencilRenderTarget;
uint32_t mCurrentSwapchainImageIndex; uint32_t mCurrentSwapchainImageIndex;
struct SwapchainImage : angle::NonCopyable struct SwapchainImage : angle::NonCopyable
......
...@@ -403,7 +403,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, ...@@ -403,7 +403,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
destOffset.y + clippedSourceArea.y - sourceArea.y, 0); destOffset.y + clippedSourceArea.y - sourceArea.y, 0);
RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget(); RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
ANGLE_TRY(colorReadRT->ensureImageInitialized(contextVk));
const vk::Format &srcFormat = colorReadRT->getImageFormat(); const vk::Format &srcFormat = colorReadRT->getImageFormat();
const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat); const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat);
...@@ -930,7 +929,7 @@ void TextureVk::setImageHelper(RendererVk *renderer, ...@@ -930,7 +929,7 @@ void TextureVk::setImageHelper(RendererVk *renderer,
mImage->initStagingBuffer(renderer, format); mImage->initStagingBuffer(renderer, format);
mRenderTarget.init(mImage, &mDrawBaseLevelImageView, getNativeImageLevel(0), mRenderTarget.init(mImage, &mDrawBaseLevelImageView, getNativeImageLevel(0),
getNativeImageLayer(0), this); getNativeImageLayer(0));
// Force re-creation of cube map render targets next time they are needed // Force re-creation of cube map render targets next time they are needed
mCubeMapRenderTargets.clear(); mCubeMapRenderTargets.clear();
...@@ -1215,7 +1214,7 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk) ...@@ -1215,7 +1214,7 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
vk::ImageView *imageView; vk::ImageView *imageView;
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, cubeMapFaceIndex, 0, &imageView)); ANGLE_TRY(getLayerLevelDrawImageView(contextVk, cubeMapFaceIndex, 0, &imageView));
mCubeMapRenderTargets[cubeMapFaceIndex].init(mImage, imageView, getNativeImageLevel(0), mCubeMapRenderTargets[cubeMapFaceIndex].init(mImage, imageView, getNativeImageLevel(0),
getNativeImageLayer(cubeMapFaceIndex), this); getNativeImageLayer(cubeMapFaceIndex));
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1285,6 +1284,8 @@ angle::Result TextureVk::initializeContents(const gl::Context *context, ...@@ -1285,6 +1284,8 @@ angle::Result TextureVk::initializeContents(const gl::Context *context,
mImage->stageSubresourceRobustClear(imageIndex, format.angleFormat()); mImage->stageSubresourceRobustClear(imageIndex, format.angleFormat());
// Note that we cannot ensure the image is initialized because we might be calling subImage
// on a non-complete cube map.
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -2150,17 +2150,14 @@ void ImageHelper::stageSubresourceEmulatedClear(const gl::ImageIndex &index, ...@@ -2150,17 +2150,14 @@ void ImageHelper::stageSubresourceEmulatedClear(const gl::ImageIndex &index,
stageSubresourceClear(index, format, kEmulatedInitColorValue, kWebGLInitDepthStencilValue); stageSubresourceClear(index, format, kEmulatedInitColorValue, kWebGLInitDepthStencilValue);
} }
angle::Result ImageHelper::clearIfEmulatedFormat(Context *context, void ImageHelper::clearIfEmulatedFormat(Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
const Format &format) const Format &format)
{ {
if (format.hasEmulatedImageChannels()) if (format.hasEmulatedImageChannels())
{ {
stageSubresourceEmulatedClear(index, format.angleFormat()); stageSubresourceEmulatedClear(index, format.angleFormat());
ANGLE_TRY(flushAllStagedUpdates(context));
} }
return angle::Result::Continue;
} }
void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index, void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index,
......
...@@ -690,9 +690,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -690,9 +690,7 @@ class ImageHelper final : public CommandGraphResource
// If the image has emulated channels, we clear them once so as not to leave garbage on those // If the image has emulated channels, we clear them once so as not to leave garbage on those
// channels. // channels.
angle::Result clearIfEmulatedFormat(Context *context, void clearIfEmulatedFormat(Context *context, const gl::ImageIndex &index, const Format &format);
const gl::ImageIndex &index,
const Format &format);
// This will use the underlying dynamic buffer to allocate some memory to be used as a src or // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
// dst. // dst.
......
...@@ -1267,6 +1267,9 @@ class SimpleStateChangeTest : public ANGLETest ...@@ -1267,6 +1267,9 @@ class SimpleStateChangeTest : public ANGLETest
void simpleDrawWithBuffer(GLBuffer *buffer); void simpleDrawWithBuffer(GLBuffer *buffer);
void simpleDrawWithColor(const GLColor &color); void simpleDrawWithColor(const GLColor &color);
using UpdateFunc = std::function<void(GLenum, GLTexture *, GLint, GLint, const GLColor &)>;
void updateTextureBoundToFramebufferHelper(UpdateFunc updateFunc);
}; };
class SimpleStateChangeTestES3 : public SimpleStateChangeTest class SimpleStateChangeTestES3 : public SimpleStateChangeTest
...@@ -1789,6 +1792,95 @@ TEST_P(SimpleStateChangeTest, UpdateTextureInUse) ...@@ -1789,6 +1792,95 @@ TEST_P(SimpleStateChangeTest, UpdateTextureInUse)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
void SimpleStateChangeTest::updateTextureBoundToFramebufferHelper(UpdateFunc updateFunc)
{
std::vector<GLColor> red(4, GLColor::red);
std::vector<GLColor> green(4, GLColor::green);
GLTexture renderTarget;
glBindTexture(GL_TEXTURE_2D, renderTarget);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, red.data());
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTarget,
0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
glViewport(0, 0, 2, 2);
ASSERT_GL_NO_ERROR();
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, red.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Draw once to flush dirty state bits.
draw2DTexturedQuad(0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Update the (0, 1) pixel to be blue
updateFunc(GL_TEXTURE_2D, &renderTarget, 0, 1, GLColor::blue);
// Draw green to the right half of the Framebuffer.
glBindTexture(GL_TEXTURE_2D, tex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, green.data());
glViewport(1, 0, 1, 2);
draw2DTexturedQuad(0.5f, 1.0f, true);
// Update the (1, 1) pixel to be yellow
updateFunc(GL_TEXTURE_2D, &renderTarget, 1, 1, GLColor::yellow);
ASSERT_GL_NO_ERROR();
// Verify we have a quad with the right colors in the FBO.
std::vector<GLColor> expected = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
std::vector<GLColor> actual(4);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, actual.data());
EXPECT_EQ(expected, actual);
}
// Tests that TexSubImage updates are flushed before rendering.
TEST_P(SimpleStateChangeTest, TexSubImageOnTextureBoundToFrambuffer)
{
auto updateFunc = [](GLenum textureBinding, GLTexture *tex, GLint x, GLint y,
const GLColor &color) {
glBindTexture(textureBinding, *tex);
glTexSubImage2D(textureBinding, 0, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color.data());
};
updateTextureBoundToFramebufferHelper(updateFunc);
}
// Tests that CopyTexSubImage updates are flushed before rendering.
TEST_P(SimpleStateChangeTest, CopyTexSubImageOnTextureBoundToFrambuffer)
{
GLTexture copySource;
glBindTexture(GL_TEXTURE_2D, copySource);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer copyFBO;
glBindFramebuffer(GL_READ_FRAMEBUFFER, copyFBO);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copySource, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER);
auto updateFunc = [&copySource](GLenum textureBinding, GLTexture *tex, GLint x, GLint y,
const GLColor &color) {
glBindTexture(GL_TEXTURE_2D, copySource);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color.data());
glBindTexture(textureBinding, *tex);
glCopyTexSubImage2D(textureBinding, 0, x, y, 0, 0, 1, 1);
};
updateTextureBoundToFramebufferHelper(updateFunc);
}
// Tests deleting a Framebuffer that is in use. // Tests deleting a Framebuffer that is in use.
TEST_P(SimpleStateChangeTest, DeleteFramebufferInUse) TEST_P(SimpleStateChangeTest, DeleteFramebufferInUse)
{ {
......
...@@ -67,6 +67,11 @@ struct SystemInfo; ...@@ -67,6 +67,11 @@ struct SystemInfo;
#define EXPECT_EGLENUM_EQ(expected, actual) \ #define EXPECT_EGLENUM_EQ(expected, actual) \
EXPECT_EQ(static_cast<EGLenum>(expected), static_cast<EGLenum>(actual)) EXPECT_EQ(static_cast<EGLenum>(expected), static_cast<EGLenum>(actual))
#define ASSERT_GL_FRAMEBUFFER_COMPLETE(framebuffer) \
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(framebuffer))
#define EXPECT_GL_FRAMEBUFFER_COMPLETE(framebuffer) \
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(framebuffer))
namespace angle namespace angle
{ {
struct GLColorRGB struct GLColorRGB
...@@ -75,6 +80,9 @@ struct GLColorRGB ...@@ -75,6 +80,9 @@ struct GLColorRGB
GLColorRGB(GLubyte r, GLubyte g, GLubyte b); GLColorRGB(GLubyte r, GLubyte g, GLubyte b);
GLColorRGB(const angle::Vector3 &floatColor); GLColorRGB(const angle::Vector3 &floatColor);
const GLubyte *data() const { return &R; }
GLubyte *data() { return &R; }
GLubyte R, G, B; GLubyte R, G, B;
static const GLColorRGB black; static const GLColorRGB black;
......
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