Commit 1b038241 by Jamie Madill

Vulkan: Support Texture redefinition.

Because initializing the texture can queue a copy from a staging vk::Image, we must ensure we're not in a render pass. To make this easier we move the current render pass tracking into the RendererVk from the FramebufferVk class. (Note: in the future we will have deferred command submission and this will become unnecessary.) BUG=angleproject:2200 Change-Id: Ide8d4d70b50efbd79bbfa7006ad75cbc57cdf4c7 Reviewed-on: https://chromium-review.googlesource.com/741549 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 91ab54b6
...@@ -307,7 +307,6 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode) ...@@ -307,7 +307,6 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode)
ASSERT(mCurrentPipeline.valid()); ASSERT(mCurrentPipeline.valid());
} }
VkDevice device = mRenderer->getDevice();
const auto &state = mState.getState(); const auto &state = mState.getState();
const auto &programGL = state.getProgram(); const auto &programGL = state.getProgram();
ProgramVk *programVk = GetImplAs<ProgramVk>(programGL); ProgramVk *programVk = GetImplAs<ProgramVk>(programGL);
...@@ -326,7 +325,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode) ...@@ -326,7 +325,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode)
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer)); ANGLE_TRY(mRenderer->getStartedCommandBuffer(&commandBuffer));
ANGLE_TRY(vkFBO->ensureInRenderPass(context, device, commandBuffer, queueSerial, state)); ANGLE_TRY(mRenderer->ensureInRenderPass(context, vkFBO));
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline); commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline);
commandBuffer->bindVertexBuffers(0, maxAttrib, vertexHandles.data(), commandBuffer->bindVertexBuffers(0, maxAttrib, vertexHandles.data(),
......
...@@ -81,20 +81,12 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state ...@@ -81,20 +81,12 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state
} }
FramebufferVk::FramebufferVk(const gl::FramebufferState &state) FramebufferVk::FramebufferVk(const gl::FramebufferState &state)
: FramebufferImpl(state), : FramebufferImpl(state), mBackbuffer(nullptr), mRenderPass(), mFramebuffer()
mBackbuffer(nullptr),
mRenderPass(),
mFramebuffer(),
mInRenderPass(false)
{ {
} }
FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer) FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer)
: FramebufferImpl(state), : FramebufferImpl(state), mBackbuffer(backbuffer), mRenderPass(), mFramebuffer()
mBackbuffer(backbuffer),
mRenderPass(),
mFramebuffer(),
mInRenderPass(false)
{ {
} }
...@@ -104,10 +96,9 @@ FramebufferVk::~FramebufferVk() ...@@ -104,10 +96,9 @@ FramebufferVk::~FramebufferVk()
void FramebufferVk::destroy(const gl::Context *context) void FramebufferVk::destroy(const gl::Context *context)
{ {
ASSERT(!mInRenderPass);
VkDevice device = GetImplAs<ContextVk>(context)->getDevice(); VkDevice device = GetImplAs<ContextVk>(context)->getDevice();
// TODO(jmadill): Deferred deletion.
mRenderPass.destroy(device); mRenderPass.destroy(device);
mFramebuffer.destroy(device); mFramebuffer.destroy(device);
} }
...@@ -290,7 +281,7 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context, ...@@ -290,7 +281,7 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer)); ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
// End render pass if we're in one. // End render pass if we're in one.
endRenderPass(commandBuffer); renderer->endRenderPass();
stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
commandBuffer); commandBuffer);
...@@ -557,19 +548,11 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const ...@@ -557,19 +548,11 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const
return gl::InternalError() << "getSamplePosition is unimplemented."; return gl::InternalError() << "getSamplePosition is unimplemented.";
} }
gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context, gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
VkDevice device, VkDevice device,
vk::CommandBuffer *commandBuffer, vk::CommandBuffer *commandBuffer,
Serial queueSerial, Serial queueSerial)
const gl::State &glState)
{ {
if (mInRenderPass)
{
return gl::NoError();
}
mInRenderPass = true;
// TODO(jmadill): Cache render targets. // TODO(jmadill): Cache render targets.
for (const auto &colorAttachment : mState.getColorAttachments()) for (const auto &colorAttachment : mState.getColorAttachments())
{ {
...@@ -598,6 +581,7 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context, ...@@ -598,6 +581,7 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context,
ASSERT(renderPass && renderPass->valid()); ASSERT(renderPass && renderPass->valid());
// TODO(jmadill): Proper clear value implementation. // TODO(jmadill): Proper clear value implementation.
const gl::State &glState = context->getGLState();
VkClearColorValue colorClear; VkClearColorValue colorClear;
memset(&colorClear, 0, sizeof(VkClearColorValue)); memset(&colorClear, 0, sizeof(VkClearColorValue));
colorClear.float32[0] = glState.getColorClearValue().red; colorClear.float32[0] = glState.getColorClearValue().red;
...@@ -627,13 +611,4 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context, ...@@ -627,13 +611,4 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context,
return gl::NoError(); return gl::NoError();
} }
void FramebufferVk::endRenderPass(vk::CommandBuffer *commandBuffer)
{
if (mInRenderPass)
{
commandBuffer->endRenderPass();
mInRenderPass = false;
}
}
} // namespace rx } // namespace rx
...@@ -83,14 +83,10 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk ...@@ -83,14 +83,10 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
gl::Error ensureInRenderPass(const gl::Context *context, gl::Error beginRenderPass(const gl::Context *context,
VkDevice device, VkDevice device,
vk::CommandBuffer *commandBuffer, vk::CommandBuffer *commandBuffer,
Serial queueSerial, Serial queueSerial);
const gl::State &glState);
void endRenderPass(vk::CommandBuffer *commandBuffer);
bool isInRenderPass() const { return mInRenderPass; }
gl::ErrorOrResult<vk::RenderPass *> getRenderPass(const gl::Context *context, VkDevice device); gl::ErrorOrResult<vk::RenderPass *> getRenderPass(const gl::Context *context, VkDevice device);
...@@ -105,7 +101,6 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk ...@@ -105,7 +101,6 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
vk::RenderPass mRenderPass; vk::RenderPass mRenderPass;
vk::Framebuffer mFramebuffer; vk::Framebuffer mFramebuffer;
bool mInRenderPass;
}; };
} // namespace rx } // namespace rx
......
...@@ -96,7 +96,8 @@ RendererVk::RendererVk() ...@@ -96,7 +96,8 @@ RendererVk::RendererVk()
mGlslangWrapper(nullptr), mGlslangWrapper(nullptr),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()), mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()), mCurrentQueueSerial(mQueueSerialFactory.generate()),
mInFlightCommands() mInFlightCommands(),
mCurrentRenderPassFramebuffer(nullptr)
{ {
} }
...@@ -785,4 +786,31 @@ Serial RendererVk::getCurrentQueueSerial() const ...@@ -785,4 +786,31 @@ Serial RendererVk::getCurrentQueueSerial() const
return mCurrentQueueSerial; return mCurrentQueueSerial;
} }
gl::Error RendererVk::ensureInRenderPass(const gl::Context *context, FramebufferVk *framebufferVk)
{
if (mCurrentRenderPassFramebuffer == framebufferVk)
{
return gl::NoError();
}
if (mCurrentRenderPassFramebuffer)
{
endRenderPass();
}
ANGLE_TRY(
framebufferVk->beginRenderPass(context, mDevice, &mCommandBuffer, mCurrentQueueSerial));
mCurrentRenderPassFramebuffer = framebufferVk;
return gl::NoError();
}
void RendererVk::endRenderPass()
{
if (mCurrentRenderPassFramebuffer)
{
ASSERT(mCommandBuffer.started());
mCommandBuffer.endRenderPass();
mCurrentRenderPassFramebuffer = nullptr;
}
}
} // namespace rx } // namespace rx
...@@ -24,6 +24,7 @@ class AttributeMap; ...@@ -24,6 +24,7 @@ class AttributeMap;
namespace rx namespace rx
{ {
class FramebufferVk;
class GlslangWrapper; class GlslangWrapper;
namespace vk namespace vk
...@@ -97,6 +98,10 @@ class RendererVk : angle::NonCopyable ...@@ -97,6 +98,10 @@ class RendererVk : angle::NonCopyable
const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; } const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; }
// TODO(jmadill): Don't keep a single renderpass in the Renderer.
gl::Error ensureInRenderPass(const gl::Context *context, FramebufferVk *framebufferVk);
void endRenderPass();
private: private:
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
...@@ -135,6 +140,9 @@ class RendererVk : angle::NonCopyable ...@@ -135,6 +140,9 @@ class RendererVk : angle::NonCopyable
std::vector<vk::FenceAndSerial> mInFlightFences; std::vector<vk::FenceAndSerial> mInFlightFences;
std::vector<vk::GarbageObject> mGarbage; std::vector<vk::GarbageObject> mGarbage;
vk::MemoryProperties mMemoryProperties; vk::MemoryProperties mMemoryProperties;
// TODO(jmadill): Don't keep a single renderpass in the Renderer.
FramebufferVk *mCurrentRenderPassFramebuffer;
}; };
} // namespace rx } // namespace rx
......
...@@ -426,8 +426,7 @@ egl::Error WindowSurfaceVk::swap(const gl::Context *context) ...@@ -426,8 +426,7 @@ egl::Error WindowSurfaceVk::swap(const gl::Context *context)
ANGLE_TRY(renderer->getStartedCommandBuffer(&currentCB)); ANGLE_TRY(renderer->getStartedCommandBuffer(&currentCB));
// End render pass // End render pass
FramebufferVk *framebufferVk = GetImplAs<FramebufferVk>(mState.defaultFramebuffer); renderer->endRenderPass();
framebufferVk->endRenderPass(currentCB);
auto &image = mSwapchainImages[mCurrentSwapchainImageIndex]; auto &image = mSwapchainImages[mCurrentSwapchainImageIndex];
......
...@@ -832,6 +832,88 @@ TEST_P(SimpleStateChangeTest, RedefineBufferInUse) ...@@ -832,6 +832,88 @@ TEST_P(SimpleStateChangeTest, RedefineBufferInUse)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Tests that deleting an in-flight Texture does not immediately delete the resource.
TEST_P(SimpleStateChangeTest, DeleteTextureInUse)
{
std::array<GLColor, 4> colors = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, true);
tex.reset();
EXPECT_GL_NO_ERROR();
int w = getWindowWidth() - 2;
int h = getWindowHeight() - 2;
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
}
// Tests that redefining an in-flight Texture does not affect the in-flight resource.
TEST_P(SimpleStateChangeTest, RedefineTextureInUse)
{
std::array<GLColor, 4> colors = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Draw with the first texture.
draw2DTexturedQuad(0.5f, 1.0f, true);
// Redefine the in-flight texture.
constexpr int kBigSize = 32;
std::vector<GLColor> bigColors;
for (int y = 0; y < kBigSize; ++y)
{
for (int x = 0; x < kBigSize; ++x)
{
bool xComp = x < kBigSize / 2;
bool yComp = y < kBigSize / 2;
if (yComp)
{
bigColors.push_back(xComp ? GLColor::cyan : GLColor::magenta);
}
else
{
bigColors.push_back(xComp ? GLColor::yellow : GLColor::white);
}
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, bigColors.data());
EXPECT_GL_NO_ERROR();
// Verify the first draw had the correct data via ReadPixels.
int w = getWindowWidth() - 2;
int h = getWindowHeight() - 2;
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
// Draw and verify with the redefined data.
draw2DTexturedQuad(0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
EXPECT_PIXEL_COLOR_EQ(w, 0, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(0, h, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::white);
}
} // anonymous namespace } // anonymous namespace
ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL()); ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
......
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