зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: Optimize updating blend state in pipeline desc
Updating blend funcs and equations always updated all 8 slots. Now that's only done for the attachments that are present. Bug: angleproject:6298 Change-Id: I58fa7e4dfa27d05fef54cc9d56c7b2aa5ef43dd8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3202550 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
This commit is contained in:
Родитель
7defdb6044
Коммит
e637e4c93b
|
@ -134,7 +134,7 @@ class FramebufferState final : angle::NonCopyable
|
|||
|
||||
bool isDefault() const;
|
||||
|
||||
const gl::Offset &getSurfaceTextureOffset() const { return mSurfaceTextureOffset; }
|
||||
const Offset &getSurfaceTextureOffset() const { return mSurfaceTextureOffset; }
|
||||
|
||||
rx::Serial getFramebufferSerial() const { return mFramebufferSerial; }
|
||||
|
||||
|
@ -156,7 +156,7 @@ class FramebufferState final : angle::NonCopyable
|
|||
FramebufferAttachment mStencilAttachment;
|
||||
|
||||
// Tracks all the color buffers attached to this FramebufferDesc
|
||||
gl::DrawBufferMask mColorAttachmentsMask;
|
||||
DrawBufferMask mColorAttachmentsMask;
|
||||
|
||||
std::vector<GLenum> mDrawBufferStates;
|
||||
GLenum mReadBufferState;
|
||||
|
@ -185,7 +185,7 @@ class FramebufferState final : angle::NonCopyable
|
|||
// EXT_sRGB_write_control
|
||||
SrgbWriteControlMode mSrgbWriteControlMode;
|
||||
|
||||
gl::Offset mSurfaceTextureOffset;
|
||||
Offset mSurfaceTextureOffset;
|
||||
};
|
||||
|
||||
class Framebuffer final : public angle::ObserverInterface,
|
||||
|
@ -328,7 +328,7 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
// Returns the offset into the texture backing the default framebuffer's surface if any. Returns
|
||||
// zero offset otherwise. The renderer will apply the offset to scissor and viewport rects used
|
||||
// for draws, clears, and blits.
|
||||
const gl::Offset &getSurfaceTextureOffset() const;
|
||||
const Offset &getSurfaceTextureOffset() const;
|
||||
|
||||
angle::Result discard(const Context *context, size_t count, const GLenum *attachments);
|
||||
angle::Result invalidate(const Context *context, size_t count, const GLenum *attachments);
|
||||
|
@ -493,8 +493,7 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
|
||||
FramebufferAttachment *getAttachmentFromSubjectIndex(angle::SubjectIndex index);
|
||||
|
||||
ANGLE_INLINE void updateFloat32ColorAttachmentBits(size_t index,
|
||||
const gl::InternalFormat *format)
|
||||
ANGLE_INLINE void updateFloat32ColorAttachmentBits(size_t index, const InternalFormat *format)
|
||||
{
|
||||
mFloat32ColorAttachmentBits.set(index, format->type == GL_FLOAT);
|
||||
}
|
||||
|
|
|
@ -3181,8 +3181,10 @@ SurfaceRotation ContextVk::getRotationReadFramebuffer() const
|
|||
return mCurrentRotationReadFramebuffer;
|
||||
}
|
||||
|
||||
void ContextVk::updateColorMasks(const gl::BlendStateExt &blendStateExt)
|
||||
void ContextVk::updateColorMasks()
|
||||
{
|
||||
const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
|
||||
|
||||
mClearColorMasks = blendStateExt.mColorMask;
|
||||
|
||||
FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
|
||||
|
@ -3191,6 +3193,20 @@ void ContextVk::updateColorMasks(const gl::BlendStateExt &blendStateExt)
|
|||
framebufferVk->getState().getEnabledDrawBuffers());
|
||||
}
|
||||
|
||||
void ContextVk::updateBlendFuncsAndEquations()
|
||||
{
|
||||
const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
|
||||
|
||||
FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
|
||||
mCachedDrawFramebufferColorAttachmentMask = framebufferVk->getState().getEnabledDrawBuffers();
|
||||
|
||||
mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition, blendStateExt,
|
||||
mCachedDrawFramebufferColorAttachmentMask);
|
||||
|
||||
mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition, blendStateExt,
|
||||
mCachedDrawFramebufferColorAttachmentMask);
|
||||
}
|
||||
|
||||
void ContextVk::updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)
|
||||
{
|
||||
// FramebufferVk::syncState could have been the origin for this call, at which point the
|
||||
|
@ -3511,15 +3527,17 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
|||
glState.getBlendColor());
|
||||
break;
|
||||
case gl::State::DIRTY_BIT_BLEND_FUNCS:
|
||||
mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition,
|
||||
glState.getBlendStateExt());
|
||||
mGraphicsPipelineDesc->updateBlendFuncs(
|
||||
&mGraphicsPipelineTransition, glState.getBlendStateExt(),
|
||||
mDrawFramebuffer->getState().getColorAttachmentsMask());
|
||||
break;
|
||||
case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
|
||||
mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition,
|
||||
glState.getBlendStateExt());
|
||||
mGraphicsPipelineDesc->updateBlendEquations(
|
||||
&mGraphicsPipelineTransition, glState.getBlendStateExt(),
|
||||
mDrawFramebuffer->getState().getColorAttachmentsMask());
|
||||
break;
|
||||
case gl::State::DIRTY_BIT_COLOR_MASK:
|
||||
updateColorMasks(glState.getBlendStateExt());
|
||||
updateColorMasks();
|
||||
break;
|
||||
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
|
||||
mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
|
||||
|
@ -3675,6 +3693,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
|||
// triggered at endRenderPass time.
|
||||
mHasDeferredFlush = true;
|
||||
}
|
||||
|
||||
gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
|
||||
mDrawFramebuffer = vk::GetImpl(drawFramebuffer);
|
||||
mDrawFramebuffer->setReadOnlyDepthFeedbackLoopMode(false);
|
||||
|
@ -3684,7 +3703,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
|||
updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
|
||||
updateViewport(mDrawFramebuffer, glState.getViewport(), glState.getNearPlane(),
|
||||
glState.getFarPlane());
|
||||
updateColorMasks(glState.getBlendStateExt());
|
||||
updateColorMasks();
|
||||
updateRasterizationSamples(mDrawFramebuffer->getSamples());
|
||||
updateRasterizerDiscardEnabled(
|
||||
mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
|
||||
|
@ -3694,6 +3713,16 @@ angle::Result ContextVk::syncState(const gl::Context *context,
|
|||
isYFlipEnabledForDrawFBO());
|
||||
updateScissor(glState);
|
||||
updateDepthStencil(glState);
|
||||
|
||||
// Clear the blend funcs/equations for color attachment indices that no longer
|
||||
// exist.
|
||||
gl::DrawBufferMask newColorAttachmentMask =
|
||||
mDrawFramebuffer->getState().getColorAttachmentsMask();
|
||||
mGraphicsPipelineDesc->resetBlendFuncsAndEquations(
|
||||
&mGraphicsPipelineTransition, mCachedDrawFramebufferColorAttachmentMask,
|
||||
newColorAttachmentMask);
|
||||
mCachedDrawFramebufferColorAttachmentMask = newColorAttachmentMask;
|
||||
|
||||
mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
|
||||
onDrawFramebufferRenderPassDescChange(mDrawFramebuffer, nullptr);
|
||||
break;
|
||||
|
|
|
@ -383,7 +383,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
|
|||
gl::TextureType type,
|
||||
gl::SamplerFormat format,
|
||||
gl::Texture **textureOut);
|
||||
void updateColorMasks(const gl::BlendStateExt &blendStateExt);
|
||||
void updateColorMasks();
|
||||
void updateBlendFuncsAndEquations();
|
||||
void updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples);
|
||||
|
||||
void handleError(VkResult errorCode,
|
||||
|
@ -1118,6 +1119,12 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
|
|||
// A list of gpu events since the last clock sync.
|
||||
std::vector<GpuEvent> mGpuEvents;
|
||||
|
||||
// Cached value of the color attachment mask of the current draw framebuffer. This is used to
|
||||
// know which attachment indices have their blend state set in |mGraphicsPipelineDesc|, and
|
||||
// subsequently is used to clear the blend state for attachments that no longer exist when a new
|
||||
// framebuffer is bound.
|
||||
gl::DrawBufferMask mCachedDrawFramebufferColorAttachmentMask;
|
||||
|
||||
bool mHasDeferredFlush;
|
||||
|
||||
// GL_EXT_shader_framebuffer_fetch_non_coherent
|
||||
|
|
|
@ -1645,8 +1645,6 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
|
|||
angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
|
||||
uint32_t colorIndexGL)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
||||
ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
|
||||
|
||||
// Update cached masks for masked clears.
|
||||
|
@ -1660,8 +1658,6 @@ angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
|
|||
const angle::Format &intendedFormat = renderTarget->getImageIntendedFormat();
|
||||
mEmulatedAlphaAttachmentMask.set(
|
||||
colorIndexGL, intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0);
|
||||
|
||||
contextVk->updateColorMasks(context->getState().getBlendStateExt());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1813,7 +1809,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
|
|||
gl::DrawBufferMask dirtyColorAttachments;
|
||||
bool dirtyDepthStencilAttachment = false;
|
||||
|
||||
bool shouldUpdateColorMask = false;
|
||||
bool shouldUpdateColorMaskAndBlend = false;
|
||||
bool shouldUpdateLayerCount = false;
|
||||
bool shouldUpdateSrgbWriteControlMode = false;
|
||||
|
||||
|
@ -1835,8 +1831,8 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
|
|||
ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
|
||||
break;
|
||||
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
|
||||
shouldUpdateColorMask = true;
|
||||
shouldUpdateLayerCount = true;
|
||||
shouldUpdateColorMaskAndBlend = true;
|
||||
shouldUpdateLayerCount = true;
|
||||
break;
|
||||
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
|
||||
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
|
||||
|
@ -1871,8 +1867,8 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
|
|||
|
||||
ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
|
||||
|
||||
shouldUpdateColorMask = true;
|
||||
shouldUpdateLayerCount = true;
|
||||
shouldUpdateColorMaskAndBlend = true;
|
||||
shouldUpdateLayerCount = true;
|
||||
dirtyColorAttachments.set(colorIndexGL);
|
||||
|
||||
break;
|
||||
|
@ -1889,9 +1885,10 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
|
|||
mRenderPassDesc.setWriteControlMode(newSrgbWriteControlMode);
|
||||
}
|
||||
|
||||
if (shouldUpdateColorMask)
|
||||
if (shouldUpdateColorMaskAndBlend)
|
||||
{
|
||||
contextVk->updateColorMasks(context->getState().getBlendStateExt());
|
||||
contextVk->updateColorMasks();
|
||||
contextVk->updateBlendFuncsAndEquations();
|
||||
}
|
||||
|
||||
if (shouldUpdateLayerCount)
|
||||
|
|
|
@ -2270,12 +2270,12 @@ void GraphicsPipelineDesc::updateBlendColor(GraphicsPipelineTransitionBits *tran
|
|||
mInputAssemblyAndColorBlendStateInfo.blendConstants[1] = color.green;
|
||||
mInputAssemblyAndColorBlendStateInfo.blendConstants[2] = color.blue;
|
||||
mInputAssemblyAndColorBlendStateInfo.blendConstants[3] = color.alpha;
|
||||
constexpr size_t kSize = sizeof(mInputAssemblyAndColorBlendStateInfo.blendConstants[0]) * 8;
|
||||
constexpr size_t kSizeBits = sizeof(mInputAssemblyAndColorBlendStateInfo.blendConstants[0]) * 8;
|
||||
|
||||
for (int index = 0; index < 4; ++index)
|
||||
{
|
||||
const size_t kBit = ANGLE_GET_INDEXED_TRANSITION_BIT(mInputAssemblyAndColorBlendStateInfo,
|
||||
blendConstants, index, kSize);
|
||||
blendConstants, index, kSizeBits);
|
||||
transition->set(kBit);
|
||||
}
|
||||
}
|
||||
|
@ -2290,12 +2290,12 @@ void GraphicsPipelineDesc::updateBlendEnabled(GraphicsPipelineTransitionBits *tr
|
|||
}
|
||||
|
||||
void GraphicsPipelineDesc::updateBlendEquations(GraphicsPipelineTransitionBits *transition,
|
||||
const gl::BlendStateExt &blendStateExt)
|
||||
const gl::BlendStateExt &blendStateExt,
|
||||
gl::DrawBufferMask attachmentMask)
|
||||
{
|
||||
constexpr size_t kSize = sizeof(PackedColorBlendAttachmentState) * 8;
|
||||
constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
|
||||
|
||||
for (size_t attachmentIndex = 0; attachmentIndex < blendStateExt.mMaxDrawBuffers;
|
||||
++attachmentIndex)
|
||||
for (size_t attachmentIndex : attachmentMask)
|
||||
{
|
||||
PackedColorBlendAttachmentState &blendAttachmentState =
|
||||
mInputAssemblyAndColorBlendStateInfo.attachments[attachmentIndex];
|
||||
|
@ -2304,16 +2304,16 @@ void GraphicsPipelineDesc::updateBlendEquations(GraphicsPipelineTransitionBits *
|
|||
blendAttachmentState.alphaBlendOp =
|
||||
PackGLBlendOp(blendStateExt.getEquationAlphaIndexed(attachmentIndex));
|
||||
transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mInputAssemblyAndColorBlendStateInfo,
|
||||
attachments, attachmentIndex, kSize));
|
||||
attachments, attachmentIndex, kSizeBits));
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
|
||||
const gl::BlendStateExt &blendStateExt)
|
||||
const gl::BlendStateExt &blendStateExt,
|
||||
gl::DrawBufferMask attachmentMask)
|
||||
{
|
||||
constexpr size_t kSize = sizeof(PackedColorBlendAttachmentState) * 8;
|
||||
for (size_t attachmentIndex = 0; attachmentIndex < blendStateExt.mMaxDrawBuffers;
|
||||
++attachmentIndex)
|
||||
constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
|
||||
for (size_t attachmentIndex : attachmentMask)
|
||||
{
|
||||
PackedColorBlendAttachmentState &blendAttachmentState =
|
||||
mInputAssemblyAndColorBlendStateInfo.attachments[attachmentIndex];
|
||||
|
@ -2326,7 +2326,34 @@ void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *tran
|
|||
blendAttachmentState.dstAlphaBlendFactor =
|
||||
PackGLBlendFactor(blendStateExt.getDstAlphaIndexed(attachmentIndex));
|
||||
transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mInputAssemblyAndColorBlendStateInfo,
|
||||
attachments, attachmentIndex, kSize));
|
||||
attachments, attachmentIndex, kSizeBits));
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsPipelineDesc::resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
|
||||
gl::DrawBufferMask previousAttachmentsMask,
|
||||
gl::DrawBufferMask newAttachmentsMask)
|
||||
{
|
||||
// A framebuffer with attachments in P was bound, and now one with attachments in N is bound.
|
||||
// We need to clear blend funcs and equations for attachments in P that are not in N. That is
|
||||
// attachments in P&~N.
|
||||
const gl::DrawBufferMask attachmentsToClear = previousAttachmentsMask & ~newAttachmentsMask;
|
||||
constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
|
||||
|
||||
for (size_t attachmentIndex : attachmentsToClear)
|
||||
{
|
||||
PackedColorBlendAttachmentState &blendAttachmentState =
|
||||
mInputAssemblyAndColorBlendStateInfo.attachments[attachmentIndex];
|
||||
|
||||
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
|
||||
transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mInputAssemblyAndColorBlendStateInfo,
|
||||
attachments, attachmentIndex, kSizeBits));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -626,9 +626,14 @@ class GraphicsPipelineDesc final
|
|||
gl::DrawBufferMask blendEnabledMask);
|
||||
void updateBlendColor(GraphicsPipelineTransitionBits *transition, const gl::ColorF &color);
|
||||
void updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
|
||||
const gl::BlendStateExt &blendStateExt);
|
||||
const gl::BlendStateExt &blendStateExt,
|
||||
gl::DrawBufferMask attachmentMask);
|
||||
void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
|
||||
const gl::BlendStateExt &blendStateExt);
|
||||
const gl::BlendStateExt &blendStateExt,
|
||||
gl::DrawBufferMask attachmentMask);
|
||||
void resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
|
||||
gl::DrawBufferMask previousAttachmentsMask,
|
||||
gl::DrawBufferMask newAttachmentsMask);
|
||||
void setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
|
||||
const gl::DrawBufferMask &alphaMask,
|
||||
const gl::DrawBufferMask &enabledDrawBuffers);
|
||||
|
|
|
@ -816,6 +816,195 @@ TEST_P(DrawBuffersTestES3, 2DArrayTextures)
|
|||
glDeleteProgram(program);
|
||||
}
|
||||
|
||||
// Test that blend works when draw buffers and framebuffers change.
|
||||
TEST_P(DrawBuffersTestES3, BlendWithDrawBufferAndFramebufferChanges)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
|
||||
|
||||
// Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
|
||||
// http://anglebug.com/3423
|
||||
ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
|
||||
|
||||
// Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
|
||||
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
|
||||
|
||||
// http://anglebug.com/5154
|
||||
ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsDesktopOpenGL());
|
||||
|
||||
// Create two framebuffers, one with 3 attachments (fbo3), one with 4 (fbo4). The test issues
|
||||
// draw calls on fbo3 with different attachments enabled, then switches to fbo4 (without
|
||||
// dirtying blend state) and draws to other attachments. It ensures that blend state is
|
||||
// appropriately set on framebuffer change.
|
||||
|
||||
GLenum bufs[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3};
|
||||
|
||||
GLFramebuffer fbo[2];
|
||||
GLTexture tex[7];
|
||||
constexpr GLfloat kClearValue[] = {1, 1, 1, 1};
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
|
||||
for (uint32_t texIndex = 0; texIndex < 7; ++texIndex)
|
||||
{
|
||||
size_t colorAttachmentIndex = texIndex >= 3 ? texIndex - 3 : texIndex;
|
||||
if (texIndex == 3)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex[texIndex]);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttachmentIndex,
|
||||
GL_TEXTURE_2D, tex[texIndex], 0);
|
||||
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
|
||||
glDrawBuffers(4, bufs);
|
||||
glClearBufferfv(GL_COLOR, colorAttachmentIndex, kClearValue);
|
||||
}
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glEnablei(GL_BLEND, 0);
|
||||
glEnablei(GL_BLEND, 1);
|
||||
glEnablei(GL_BLEND, 2);
|
||||
glEnablei(GL_BLEND, 3);
|
||||
|
||||
glBlendEquationi(0, GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendEquationi(1, GL_MIN);
|
||||
glBlendEquationi(2, GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendEquationi(3, GL_FUNC_REVERSE_SUBTRACT);
|
||||
|
||||
glBlendFunci(0, GL_ONE, GL_ONE);
|
||||
glBlendFunci(1, GL_DST_ALPHA, GL_DST_ALPHA);
|
||||
glBlendFunci(2, GL_SRC_ALPHA, GL_SRC_ALPHA);
|
||||
glBlendFunci(3, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
|
||||
|
||||
bufs[0] = GL_NONE;
|
||||
bufs[2] = GL_NONE;
|
||||
glDrawBuffers(4, bufs);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
|
||||
bufs[2] = GL_COLOR_ATTACHMENT2;
|
||||
glDrawBuffers(3, bufs);
|
||||
|
||||
constexpr char kFS[] = R"(#version 300 es
|
||||
precision highp float;
|
||||
|
||||
uniform vec4 value0;
|
||||
uniform vec4 value1;
|
||||
uniform vec4 value2;
|
||||
uniform vec4 value3;
|
||||
|
||||
layout(location = 0) out vec4 color0;
|
||||
layout(location = 1) out vec4 color1;
|
||||
layout(location = 2) out vec4 color2;
|
||||
layout(location = 3) out vec4 color3;
|
||||
|
||||
void main()
|
||||
{
|
||||
color0 = value0;
|
||||
color1 = value1;
|
||||
color2 = value2;
|
||||
color3 = value3;
|
||||
}
|
||||
)";
|
||||
|
||||
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
|
||||
glUseProgram(program);
|
||||
|
||||
GLint uniforms[4];
|
||||
for (uint32_t attachmentIndex = 0; attachmentIndex < 4; ++attachmentIndex)
|
||||
{
|
||||
char uniformName[20];
|
||||
snprintf(uniformName, sizeof uniformName, "value%u", attachmentIndex);
|
||||
uniforms[attachmentIndex] = glGetUniformLocation(program, uniformName);
|
||||
ASSERT_NE(uniforms[attachmentIndex], -1);
|
||||
}
|
||||
|
||||
// Currently, fbo3 is bound. The attachment states are:
|
||||
//
|
||||
// 0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
|
||||
// 1: Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
|
||||
// 2: Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
|
||||
//
|
||||
// Draw:
|
||||
//
|
||||
// 0: Color: don't care
|
||||
// 1: Color: (0.75, 0.5, 0.25, 0.5) -> Result after blend is: (0.75, 0.5, 0.25, 0.5)
|
||||
// 2: Color: (0.25, 0.5, 0.75, 0.5) -> Result after blend is: (0.375, 0.25, 0.125, 0.25)
|
||||
|
||||
// Draws green into attachment 1
|
||||
glUniform4f(uniforms[1], 0.75, 0.5, 0.25, 0.5);
|
||||
glUniform4f(uniforms[2], 0.25, 0.5, 0.75, 0.5);
|
||||
drawQuad(program, positionAttrib(), 0.5);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
bufs[0] = GL_COLOR_ATTACHMENT0;
|
||||
bufs[1] = GL_NONE;
|
||||
glDrawBuffers(3, bufs);
|
||||
|
||||
// Currently, fbo3 is bound. The attachment states are:
|
||||
//
|
||||
// 0: Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
|
||||
// 1: DISABLED Color: (0.75, 0.5, 0.25, 0.5), Blend: min, DST_ALPHA/DST_ALPHA
|
||||
// 2: Color: (0.375, 0.25, 0.125, 0.25), Blend: reverse subtract,
|
||||
// SRC_ALPHA/SRC_ALPHA
|
||||
//
|
||||
// Draw:
|
||||
//
|
||||
// 0: Color: (0.5, 0.25, 0.75, 0.25) -> Result after blend is: (0.5, 0.75, 0.25, 0.75)
|
||||
// 1: Color: don't care
|
||||
// 2: Color: (0.125, 0, 0, 1) -> Result after blend is: (0.25, 0.25, 0.125, 0)
|
||||
|
||||
// Clear with red
|
||||
glUniform4f(uniforms[0], 0.5, 0.25, 0.75, 0.25);
|
||||
glUniform4f(uniforms[2], 0.125, 0, 0, 1);
|
||||
drawQuad(program, positionAttrib(), 0.5);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
|
||||
|
||||
// Currently, fbo4 is bound. The attachment states are:
|
||||
//
|
||||
// 0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
|
||||
// 1: Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
|
||||
// 2: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
|
||||
// 3: Color: (1, 1, 1, 1), Blend: reverse subtract, ONE_MINUS_SRC_ALPHA/SRC_ALPHA
|
||||
//
|
||||
// Draw:
|
||||
//
|
||||
// 0: Color: don't care
|
||||
// 1: Color: (0.125, 0.5, 0.625, 0.25) -> Result after blend is: (0.125, 0.5, 0.625, 0.25)
|
||||
// 2: Color: don't care
|
||||
// 3: Color: (0.75, 0.25, 0.5, 0.75) -> Result after blend is:
|
||||
// (0.5625, 0.6875, 0.625, 0.5625)
|
||||
|
||||
glUniform4f(uniforms[1], 0.125, 0.5, 0.625, 0.25);
|
||||
glUniform4f(uniforms[3], 0.75, 0.25, 0.5, 0.75);
|
||||
drawQuad(program, positionAttrib(), 0.5);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Verify results
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 127, 191, 63, 191, 1);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT1);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 191, 127, 63, 127, 1);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT2);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 63, 63, 31, 0, 1);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT1);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 31, 127, 159, 63, 1);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT2);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT3);
|
||||
EXPECT_PIXEL_NEAR(0, 0, 143, 175, 159, 143, 1);
|
||||
}
|
||||
|
||||
// Vulkan backend is setting per buffer color mask to false for draw buffers that set to GL_NONE.
|
||||
// These set of tests are to test draw buffer change followed by draw/clear/blit and followed by
|
||||
// draw buffer change are behaving correctly.
|
||||
|
|
Загрузка…
Ссылка в новой задаче