Commit c12c1f57 by Alexey Knyazev Committed by Commit Bot

D3D11: Skip setting BlendState for integer attachments

Some D3D11 drivers may produce unexpected results when blending is apllied to integer attachments. Minor cleanup: early exit for nullptr attachments. New BlendIntegerTest in angle_end2end. Bug: angleproject:4548, angleproject:4547, angleproject:4525, angleproject:4394 Change-Id: I236ac6db1f8dcaca54e9bc1b0803e1775fd75632 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2134448 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent dac5cc3b
...@@ -70,15 +70,15 @@ d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *conte ...@@ -70,15 +70,15 @@ d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *conte
// enforcing default values. // enforcing default values.
keyBlendState = gl::BlendState(); keyBlendState = gl::BlendState();
if (blendState.blend) ASSERT(keyBlendIndex < colorbuffers.size());
const gl::FramebufferAttachment *attachment = colorbuffers[keyBlendIndex];
// Do not set blend state for null attachments that may be present when
// mrt_perf_workaround is disabled.
if (attachment == nullptr)
{ {
keyBlendState.blend = true; keyBlendIndex++;
keyBlendState.sourceBlendRGB = blendState.sourceBlendRGB; continue;
keyBlendState.sourceBlendAlpha = blendState.sourceBlendAlpha;
keyBlendState.destBlendRGB = blendState.destBlendRGB;
keyBlendState.destBlendAlpha = blendState.destBlendAlpha;
keyBlendState.blendEquationRGB = blendState.blendEquationRGB;
keyBlendState.blendEquationAlpha = blendState.blendEquationAlpha;
} }
// These values are used only for caching (hash calculation) purposes. // These values are used only for caching (hash calculation) purposes.
...@@ -88,16 +88,26 @@ d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *conte ...@@ -88,16 +88,26 @@ d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *conte
keyBlendState.colorMaskBlue = blendState.colorMaskBlue; keyBlendState.colorMaskBlue = blendState.colorMaskBlue;
keyBlendState.colorMaskAlpha = blendState.colorMaskAlpha; keyBlendState.colorMaskAlpha = blendState.colorMaskAlpha;
ASSERT(keyBlendIndex < colorbuffers.size()); const gl::InternalFormat &internalFormat = *attachment->getFormat().info;
const gl::FramebufferAttachment *attachment = colorbuffers[keyBlendIndex];
key.rtvMax = static_cast<uint16_t>(keyBlendIndex) + 1;
key.rtvMasks[keyBlendIndex] =
gl_d3d11::GetColorMask(internalFormat) &
gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha);
if (attachment) // when mrt_perf_workaround is disabled, nullptr attachments may exist // Some D3D11 drivers produce unexpected results when blending is enabled for integer
// attachments. Per OpenGL ES spec, it must be ignored anyway. When blending is disabled,
// the state remains default to reduce the number of unique keys.
if (blendState.blend && !internalFormat.isInt())
{ {
key.rtvMax = static_cast<uint16_t>(keyBlendIndex) + 1; keyBlendState.blend = true;
key.rtvMasks[keyBlendIndex] = keyBlendState.sourceBlendRGB = blendState.sourceBlendRGB;
(gl_d3d11::GetColorMask(*attachment->getFormat().info)) & keyBlendState.sourceBlendAlpha = blendState.sourceBlendAlpha;
gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, keyBlendState.destBlendRGB = blendState.destBlendRGB;
blendState.colorMaskBlue, blendState.colorMaskAlpha); keyBlendState.destBlendAlpha = blendState.destBlendAlpha;
keyBlendState.blendEquationRGB = blendState.blendEquationRGB;
keyBlendState.blendEquationAlpha = blendState.blendEquationAlpha;
} }
keyBlendIndex++; keyBlendIndex++;
} }
......
...@@ -27,6 +27,7 @@ angle_end2end_tests_sources = [ ...@@ -27,6 +27,7 @@ angle_end2end_tests_sources = [
"gl_tests/BindGeneratesResourceTest.cpp", "gl_tests/BindGeneratesResourceTest.cpp",
"gl_tests/BindUniformLocationTest.cpp", "gl_tests/BindUniformLocationTest.cpp",
"gl_tests/BlendFuncExtendedTest.cpp", "gl_tests/BlendFuncExtendedTest.cpp",
"gl_tests/BlendIntegerTest.cpp",
"gl_tests/BlendMinMaxTest.cpp", "gl_tests/BlendMinMaxTest.cpp",
"gl_tests/BlitFramebufferANGLETest.cpp", "gl_tests/BlitFramebufferANGLETest.cpp",
"gl_tests/BufferDataTest.cpp", "gl_tests/BufferDataTest.cpp",
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
class BlendIntegerTest : public ANGLETest
{
protected:
BlendIntegerTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
template <typename T, GLuint components>
void compareValue(const T *value, const char *name)
{
T pixel[4];
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER,
std::is_same<T, int32_t>::value ? GL_INT : GL_UNSIGNED_INT, pixel);
for (size_t componentIdx = 0; componentIdx < components; componentIdx++)
{
EXPECT_EQ(value[componentIdx], pixel[componentIdx])
<< " componentIdx=" << componentIdx << std::endl
<< " " << name << "[0]=" << value[0] << " pixel[0]=" << pixel[0] << std::endl
<< " " << name << "[1]=" << value[1] << " pixel[1]=" << pixel[1] << std::endl
<< " " << name << "[2]=" << value[2] << " pixel[2]=" << pixel[2] << std::endl
<< " " << name << "[3]=" << value[3] << " pixel[3]=" << pixel[3];
}
}
template <GLenum internalformat, GLuint components, bool isSigned>
void runTest()
{
// https://crbug.com/angleproject/4548
ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsIntel() && !isVulkanSwiftshaderRenderer());
constexpr char kFsui[] =
"#version 300 es\n"
"out highp uvec4 o_drawBuffer0;\n"
"void main(void)\n"
"{\n"
" o_drawBuffer0 = uvec4(1, 1, 1, 1);\n"
"}\n";
constexpr char kFssi[] =
"#version 300 es\n"
"out highp ivec4 o_drawBuffer0;\n"
"void main(void)\n"
"{\n"
" o_drawBuffer0 = ivec4(-1, -1, -1, -1);\n"
"}\n";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), isSigned ? kFssi : kFsui);
glUseProgram(program);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
GLRenderbuffer colorRenderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, internalformat, getWindowWidth(), getWindowHeight());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
colorRenderbuffer);
if (isSigned)
{
const int32_t clearValueSigned[4] = {-128, -128, -128, -128};
glClearBufferiv(GL_COLOR, 0, clearValueSigned);
ASSERT_GL_NO_ERROR();
compareValue<int32_t, components>(clearValueSigned, "clearValueSigned");
}
else
{
const uint32_t clearValueUnsigned[4] = {127, 127, 127, 3};
glClearBufferuiv(GL_COLOR, 0, clearValueUnsigned);
ASSERT_GL_NO_ERROR();
compareValue<uint32_t, components>(clearValueUnsigned, "clearValueUnsigned");
}
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Enabled blending must be ignored for integer color attachment.
if (isSigned)
{
const int32_t colorValueSigned[4] = {-1, -1, -1, -1};
compareValue<int32_t, components>(colorValueSigned, "colorValueSigned");
}
else
{
const uint32_t colorValueUnsigned[4] = {1, 1, 1, 1};
compareValue<uint32_t, components>(colorValueUnsigned, "colorValueUnsigned");
}
}
};
// Test that blending is not applied to signed integer attachments.
TEST_P(BlendIntegerTest, R8I)
{
runTest<GL_R8I, 1, true>();
}
TEST_P(BlendIntegerTest, R16I)
{
runTest<GL_R16I, 1, true>();
}
TEST_P(BlendIntegerTest, R32I)
{
runTest<GL_R32I, 1, true>();
}
TEST_P(BlendIntegerTest, RG8I)
{
runTest<GL_RG8I, 2, true>();
}
TEST_P(BlendIntegerTest, RG16I)
{
runTest<GL_RG16I, 2, true>();
}
TEST_P(BlendIntegerTest, RG32I)
{
runTest<GL_RG32I, 2, true>();
}
TEST_P(BlendIntegerTest, RGBA8I)
{
runTest<GL_RGBA8I, 4, true>();
}
TEST_P(BlendIntegerTest, RGBA16I)
{
runTest<GL_RGBA16I, 4, true>();
}
TEST_P(BlendIntegerTest, RGBA32I)
{
runTest<GL_RGBA32I, 4, true>();
}
// Test that blending is not applied to unsigned integer attachments.
TEST_P(BlendIntegerTest, R8UI)
{
runTest<GL_R8UI, 1, false>();
}
TEST_P(BlendIntegerTest, R16UI)
{
runTest<GL_R16UI, 1, false>();
}
TEST_P(BlendIntegerTest, R32UI)
{
runTest<GL_R32UI, 1, false>();
}
TEST_P(BlendIntegerTest, RG8UI)
{
runTest<GL_RG8UI, 2, false>();
}
TEST_P(BlendIntegerTest, RG16UI)
{
runTest<GL_RG16UI, 2, false>();
}
TEST_P(BlendIntegerTest, RG32UI)
{
runTest<GL_RG32UI, 2, false>();
}
TEST_P(BlendIntegerTest, RGBA8UI)
{
runTest<GL_RGBA8UI, 4, false>();
}
TEST_P(BlendIntegerTest, RGBA16UI)
{
runTest<GL_RGBA16UI, 4, false>();
}
TEST_P(BlendIntegerTest, RGBA32UI)
{
runTest<GL_RGBA32UI, 4, false>();
}
TEST_P(BlendIntegerTest, RGB10_A2UI)
{
runTest<GL_RGB10_A2UI, 4, false>();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES3(BlendIntegerTest);
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