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)
ASSERT(mCurrentPipeline.valid());
}
VkDevice device = mRenderer->getDevice();
const auto &state = mState.getState();
const auto &programGL = state.getProgram();
ProgramVk *programVk = GetImplAs<ProgramVk>(programGL);
......@@ -326,7 +325,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context, GLenum mode)
vk::CommandBuffer *commandBuffer = nullptr;
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->bindVertexBuffers(0, maxAttrib, vertexHandles.data(),
......
......@@ -81,20 +81,12 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state
}
FramebufferVk::FramebufferVk(const gl::FramebufferState &state)
: FramebufferImpl(state),
mBackbuffer(nullptr),
mRenderPass(),
mFramebuffer(),
mInRenderPass(false)
: FramebufferImpl(state), mBackbuffer(nullptr), mRenderPass(), mFramebuffer()
{
}
FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer)
: FramebufferImpl(state),
mBackbuffer(backbuffer),
mRenderPass(),
mFramebuffer(),
mInRenderPass(false)
: FramebufferImpl(state), mBackbuffer(backbuffer), mRenderPass(), mFramebuffer()
{
}
......@@ -104,10 +96,9 @@ FramebufferVk::~FramebufferVk()
void FramebufferVk::destroy(const gl::Context *context)
{
ASSERT(!mInRenderPass);
VkDevice device = GetImplAs<ContextVk>(context)->getDevice();
// TODO(jmadill): Deferred deletion.
mRenderPass.destroy(device);
mFramebuffer.destroy(device);
}
......@@ -290,7 +281,7 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
ANGLE_TRY(contextVk->getStartedCommandBuffer(&commandBuffer));
// End render pass if we're in one.
endRenderPass(commandBuffer);
renderer->endRenderPass();
stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
commandBuffer);
......@@ -557,19 +548,11 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const
return gl::InternalError() << "getSamplePosition is unimplemented.";
}
gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context,
VkDevice device,
vk::CommandBuffer *commandBuffer,
Serial queueSerial,
const gl::State &glState)
gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
VkDevice device,
vk::CommandBuffer *commandBuffer,
Serial queueSerial)
{
if (mInRenderPass)
{
return gl::NoError();
}
mInRenderPass = true;
// TODO(jmadill): Cache render targets.
for (const auto &colorAttachment : mState.getColorAttachments())
{
......@@ -598,6 +581,7 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context,
ASSERT(renderPass && renderPass->valid());
// TODO(jmadill): Proper clear value implementation.
const gl::State &glState = context->getGLState();
VkClearColorValue colorClear;
memset(&colorClear, 0, sizeof(VkClearColorValue));
colorClear.float32[0] = glState.getColorClearValue().red;
......@@ -627,13 +611,4 @@ gl::Error FramebufferVk::ensureInRenderPass(const gl::Context *context,
return gl::NoError();
}
void FramebufferVk::endRenderPass(vk::CommandBuffer *commandBuffer)
{
if (mInRenderPass)
{
commandBuffer->endRenderPass();
mInRenderPass = false;
}
}
} // namespace rx
......@@ -83,14 +83,10 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
gl::Error ensureInRenderPass(const gl::Context *context,
VkDevice device,
vk::CommandBuffer *commandBuffer,
Serial queueSerial,
const gl::State &glState);
void endRenderPass(vk::CommandBuffer *commandBuffer);
bool isInRenderPass() const { return mInRenderPass; }
gl::Error beginRenderPass(const gl::Context *context,
VkDevice device,
vk::CommandBuffer *commandBuffer,
Serial queueSerial);
gl::ErrorOrResult<vk::RenderPass *> getRenderPass(const gl::Context *context, VkDevice device);
......@@ -105,7 +101,6 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
vk::RenderPass mRenderPass;
vk::Framebuffer mFramebuffer;
bool mInRenderPass;
};
} // namespace rx
......
......@@ -96,7 +96,8 @@ RendererVk::RendererVk()
mGlslangWrapper(nullptr),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
mInFlightCommands()
mInFlightCommands(),
mCurrentRenderPassFramebuffer(nullptr)
{
}
......@@ -785,4 +786,31 @@ Serial RendererVk::getCurrentQueueSerial() const
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
......@@ -24,6 +24,7 @@ class AttributeMap;
namespace rx
{
class FramebufferVk;
class GlslangWrapper;
namespace vk
......@@ -97,6 +98,10 @@ class RendererVk : angle::NonCopyable
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:
void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps,
......@@ -135,6 +140,9 @@ class RendererVk : angle::NonCopyable
std::vector<vk::FenceAndSerial> mInFlightFences;
std::vector<vk::GarbageObject> mGarbage;
vk::MemoryProperties mMemoryProperties;
// TODO(jmadill): Don't keep a single renderpass in the Renderer.
FramebufferVk *mCurrentRenderPassFramebuffer;
};
} // namespace rx
......
......@@ -426,8 +426,7 @@ egl::Error WindowSurfaceVk::swap(const gl::Context *context)
ANGLE_TRY(renderer->getStartedCommandBuffer(&currentCB));
// End render pass
FramebufferVk *framebufferVk = GetImplAs<FramebufferVk>(mState.defaultFramebuffer);
framebufferVk->endRenderPass(currentCB);
renderer->endRenderPass();
auto &image = mSwapchainImages[mCurrentSwapchainImageIndex];
......
......@@ -832,6 +832,88 @@ TEST_P(SimpleStateChangeTest, RedefineBufferInUse)
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
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