Commit db9e5d31 by Corentin Wallez Committed by Commit Bot

D3D11: Only apply attachments that are written by the program

This works around a bug in the AMD driver that writes 0's to the first attachment if it isn't written by the pixel shader. BUG=angleproject:2048 Change-Id: I384fd60c0e0a37fbc0fd7b69fe1ec74fe4ffac8f Reviewed-on: https://chromium-review.googlesource.com/531630Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent cce8965d
......@@ -379,6 +379,7 @@ class Program final : angle::NonCopyable, public LabeledObject
{
return mState.mOutputVariableTypes;
}
DrawBufferMask getActiveOutputVariables() const { return mState.mActiveOutputVariables; }
void getActiveUniform(GLuint index,
GLsizei bufsize,
......
......@@ -301,11 +301,9 @@ bool FramebufferD3D::checkStatus() const
void FramebufferD3D::syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits)
{
bool invalidateColorAttachmentCache = false;
if (!mColorAttachmentsForRender.valid())
{
invalidateColorAttachmentCache = true;
return;
}
for (auto dirtyBit : dirtyBits)
......@@ -314,13 +312,19 @@ void FramebufferD3D::syncState(const gl::Context *context,
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||
dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS)
{
invalidateColorAttachmentCache = true;
mColorAttachmentsForRender.reset();
}
}
}
const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context)
{
gl::DrawBufferMask activeProgramOutputs =
context->getContextState().getState().getProgram()->getActiveOutputVariables();
if (!invalidateColorAttachmentCache)
if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs)
{
return;
return mColorAttachmentsForRender.value();
}
// Does not actually free memory
......@@ -335,7 +339,8 @@ void FramebufferD3D::syncState(const gl::Context *context,
GLenum drawBufferState = drawBufferStates[attachmentIndex];
const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex];
if (colorAttachment.isAttached() && drawBufferState != GL_NONE)
if (colorAttachment.isAttached() && drawBufferState != GL_NONE &&
activeProgramOutputs[attachmentIndex])
{
ASSERT(drawBufferState == GL_BACK ||
drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex));
......@@ -348,11 +353,8 @@ void FramebufferD3D::syncState(const gl::Context *context,
}
mColorAttachmentsForRender = std::move(colorAttachmentsForRender);
}
mCurrentActiveProgramOutputs = activeProgramOutputs;
const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender() const
{
ASSERT(mColorAttachmentsForRender.valid());
return mColorAttachmentsForRender.value();
}
......
......@@ -97,7 +97,7 @@ class FramebufferD3D : public FramebufferImpl
void syncState(const gl::Context *context,
const gl::Framebuffer::DirtyBits &dirtyBits) override;
const gl::AttachmentList &getColorAttachmentsForRender() const;
const gl::AttachmentList &getColorAttachmentsForRender(const gl::Context *context);
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
......@@ -126,6 +126,7 @@ class FramebufferD3D : public FramebufferImpl
RendererD3D *mRenderer;
Optional<gl::AttachmentList> mColorAttachmentsForRender;
gl::DrawBufferMask mCurrentActiveProgramOutputs;
};
}
......
......@@ -1133,13 +1133,14 @@ void ProgramD3D::setSeparable(bool /* separable */)
{
}
gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Context *context,
const gl::Framebuffer *fbo,
ShaderExecutableD3D **outExecutable)
{
mPixelShaderOutputFormatCache.clear();
const FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(fbo);
const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender();
FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(fbo);
const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(context);
for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
{
......
......@@ -165,7 +165,8 @@ class ProgramD3D : public ProgramImpl
void setBinaryRetrievableHint(bool retrievable) override;
void setSeparable(bool separable) override;
gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
gl::Error getPixelExecutableForFramebuffer(const gl::Context *context,
const gl::Framebuffer *fbo,
ShaderExecutableD3D **outExectuable);
gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout,
ShaderExecutableD3D **outExectuable,
......
......@@ -44,12 +44,13 @@ void RenderStateCache::clear()
}
// static
d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Framebuffer *framebuffer,
d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context,
const gl::Framebuffer *framebuffer,
const gl::BlendState &blendState)
{
d3d11::BlendStateKey key;
const FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer);
const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender();
FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer);
const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(context);
const UINT8 blendStateMask =
gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha);
......
......@@ -71,7 +71,8 @@ class RenderStateCache : angle::NonCopyable
void clear();
static d3d11::BlendStateKey GetBlendStateKey(const gl::Framebuffer *framebuffer,
static d3d11::BlendStateKey GetBlendStateKey(const gl::Context *context,
const gl::Framebuffer *framebuffer,
const gl::BlendState &blendState);
gl::Error getBlendState(Renderer11 *renderer,
const d3d11::BlendStateKey &key,
......
......@@ -1845,12 +1845,13 @@ gl::Error Renderer11::applyTransformFeedbackBuffers(const gl::ContextState &data
return gl::NoError();
}
gl::Error Renderer11::drawArraysImpl(const gl::ContextState &data,
gl::Error Renderer11::drawArraysImpl(const gl::Context *context,
GLenum mode,
GLint startVertex,
GLsizei count,
GLsizei instances)
{
const auto &data = context->getContextState();
const auto &glState = data.getState();
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
......@@ -1872,8 +1873,8 @@ gl::Error Renderer11::drawArraysImpl(const gl::ContextState &data,
}
rx::ShaderExecutableD3D *pixelExe = nullptr;
ANGLE_TRY(
programD3D->getPixelExecutableForFramebuffer(glState.getDrawFramebuffer(), &pixelExe));
ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(
context, glState.getDrawFramebuffer(), &pixelExe));
// Skip the draw call if rasterizer discard is enabled (or no fragment shader).
if (!pixelExe || glState.getRasterizerState().rasterizerDiscard)
......@@ -2358,11 +2359,12 @@ gl::Error Renderer11::drawTriangleFan(const gl::ContextState &data,
return gl::NoError();
}
gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode)
gl::Error Renderer11::applyShaders(const gl::Context *context, GLenum drawMode)
{
// This method is called single-threaded.
ANGLE_TRY(ensureHLSLCompilerInitialized());
const auto &data = context->getContextState();
const auto &glState = data.getState();
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
programD3D->updateCachedInputLayout(glState);
......@@ -2374,7 +2376,7 @@ gl::Error Renderer11::applyShaders(const gl::ContextState &data, GLenum drawMode
const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
ShaderExecutableD3D *pixelExe = nullptr;
ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe));
ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(context, drawFramebuffer, &pixelExe));
ShaderExecutableD3D *geometryExe = nullptr;
ANGLE_TRY(
......@@ -4621,7 +4623,7 @@ gl::Error Renderer11::genericDrawElements(const gl::Context *context,
ANGLE_TRY(applyVertexBuffer(context, mode, static_cast<GLsizei>(indexInfo.indexRange.start),
static_cast<GLsizei>(vertexCount), instances, &indexInfo));
ANGLE_TRY(applyTextures(context));
ANGLE_TRY(applyShaders(data, mode));
ANGLE_TRY(applyShaders(context, mode));
ANGLE_TRY(programD3D->applyUniformBuffers(data));
if (!skipDraw(data, mode))
......@@ -4657,12 +4659,12 @@ gl::Error Renderer11::genericDrawArrays(const gl::Context *context,
ANGLE_TRY(applyTransformFeedbackBuffers(data));
ANGLE_TRY(applyVertexBuffer(context, mode, first, count, instances, nullptr));
ANGLE_TRY(applyTextures(context));
ANGLE_TRY(applyShaders(data, mode));
ANGLE_TRY(applyShaders(context, mode));
ANGLE_TRY(programD3D->applyUniformBuffers(data));
if (!skipDraw(data, mode))
{
ANGLE_TRY(drawArraysImpl(data, mode, first, count, instances));
ANGLE_TRY(drawArraysImpl(context, mode, first, count, instances));
if (glState.isTransformFeedbackActiveUnpaused())
{
......@@ -4692,7 +4694,7 @@ gl::Error Renderer11::genericDrawIndirect(const gl::Context *context,
ANGLE_TRY(applyTransformFeedbackBuffers(contextState));
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
ANGLE_TRY(applyTextures(context));
ANGLE_TRY(applyShaders(contextState, mode));
ANGLE_TRY(applyShaders(context, mode));
ANGLE_TRY(programD3D->applyUniformBuffers(contextState));
if (type == GL_NONE)
......
......@@ -479,7 +479,7 @@ class Renderer11 : public RendererD3D
size_t rangeEnd) override;
private:
gl::Error drawArraysImpl(const gl::ContextState &data,
gl::Error drawArraysImpl(const gl::Context *context,
GLenum mode,
GLint startVertex,
GLsizei count,
......@@ -520,7 +520,7 @@ class Renderer11 : public RendererD3D
int baseVertex,
int instances);
gl::Error applyShaders(const gl::ContextState &data, GLenum drawMode);
gl::Error applyShaders(const gl::Context *context, GLenum drawMode);
gl::Error generateSwizzle(const gl::Context *context, gl::Texture *texture);
gl::Error generateSwizzles(const gl::Context *context, gl::SamplerType type);
gl::Error generateSwizzles(const gl::Context *context);
......
......@@ -503,7 +503,8 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
// TODO(jmadill): Input layout and vertex buffer state.
}
gl::Error StateManager11::syncBlendState(const gl::Framebuffer *framebuffer,
gl::Error StateManager11::syncBlendState(const gl::Context *context,
const gl::Framebuffer *framebuffer,
const gl::BlendState &blendState,
const gl::ColorF &blendColor,
unsigned int sampleMask)
......@@ -514,7 +515,8 @@ gl::Error StateManager11::syncBlendState(const gl::Framebuffer *framebuffer,
}
ID3D11BlendState *dxBlendState = nullptr;
const d3d11::BlendStateKey &key = RenderStateCache::GetBlendStateKey(framebuffer, blendState);
const d3d11::BlendStateKey &key =
RenderStateCache::GetBlendStateKey(context, framebuffer, blendState);
ANGLE_TRY(mRenderer->getBlendState(key, &dxBlendState));
......@@ -1053,6 +1055,8 @@ gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Frameb
size_t appliedRTIndex = 0;
bool skipInactiveRTs = mRenderer->getWorkarounds().mrtPerfWorkaround;
const auto &drawStates = framebuffer->getDrawBufferStates();
gl::DrawBufferMask activeProgramOutputs =
context->getContextState().getState().getProgram()->getActiveOutputVariables();
UINT maxExistingRT = 0;
for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex)
......@@ -1060,7 +1064,8 @@ gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Frameb
const RenderTarget11 *renderTarget = colorRTs[rtIndex];
// Skip inactive rendertargets if the workaround is enabled.
if (skipInactiveRTs && (!renderTarget || drawStates[rtIndex] == GL_NONE))
if (skipInactiveRTs &&
(!renderTarget || drawStates[rtIndex] == GL_NONE || !activeProgramOutputs[rtIndex]))
{
continue;
}
......@@ -1279,7 +1284,8 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
// Setting blend state
unsigned int mask = GetBlendSampleMask(data, samples);
ANGLE_TRY(syncBlendState(framebuffer, glState.getBlendState(), glState.getBlendColor(), mask));
ANGLE_TRY(syncBlendState(context, framebuffer, glState.getBlendState(), glState.getBlendColor(),
mask));
// Setting depth stencil state
ANGLE_TRY(syncDepthStencilState(glState));
......
......@@ -55,6 +55,7 @@ class StateManager11 final : angle::NonCopyable
void initialize(const gl::Caps &caps);
void deinitialize();
void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits);
const dx_VertexConstants11 &getVertexConstants() const { return mVertexConstants; }
......@@ -111,7 +112,8 @@ class StateManager11 final : angle::NonCopyable
void unsetConflictingAttachmentResources(const gl::FramebufferAttachment *attachment,
ID3D11Resource *resource);
gl::Error syncBlendState(const gl::Framebuffer *framebuffer,
gl::Error syncBlendState(const gl::Context *context,
const gl::Framebuffer *framebuffer,
const gl::BlendState &blendState,
const gl::ColorF &blendColor,
unsigned int sampleMask);
......
......@@ -1778,22 +1778,23 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou
return gl::NoError();
}
gl::Error Renderer9::applyShaders(const gl::ContextState &data, GLenum drawMode)
gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode)
{
const gl::State &state = context->getContextState().getState();
// This method is called single-threaded.
ANGLE_TRY(ensureHLSLCompilerInitialized());
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.getState().getProgram());
programD3D->updateCachedInputLayout(data.getState());
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(state.getProgram());
programD3D->updateCachedInputLayout(state);
const auto &inputLayout = programD3D->getCachedInputLayout();
ShaderExecutableD3D *vertexExe = nullptr;
ANGLE_TRY(programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr));
const gl::Framebuffer *drawFramebuffer = data.getState().getDrawFramebuffer();
const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer();
ShaderExecutableD3D *pixelExe = nullptr;
ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe));
ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(context, drawFramebuffer, &pixelExe));
IDirect3DVertexShader9 *vertexShader =
(vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr);
......@@ -3146,7 +3147,7 @@ gl::Error Renderer9::genericDrawElements(const gl::Context *context,
static_cast<GLsizei>(indexInfo.indexRange.start),
static_cast<GLsizei>(vertexCount), instances, &indexInfo));
ANGLE_TRY(applyTextures(context));
ANGLE_TRY(applyShaders(data, mode));
ANGLE_TRY(applyShaders(context, mode));
ANGLE_TRY(programD3D->applyUniformBuffers(data));
if (!skipDraw(data, mode))
......@@ -3180,7 +3181,7 @@ gl::Error Renderer9::genericDrawArrays(const gl::Context *context,
ANGLE_TRY(applyTransformFeedbackBuffers(data.getState()));
ANGLE_TRY(applyVertexBuffer(data.getState(), mode, first, count, instances, nullptr));
ANGLE_TRY(applyTextures(context));
ANGLE_TRY(applyShaders(data, mode));
ANGLE_TRY(applyShaders(context, mode));
ANGLE_TRY(programD3D->applyUniformBuffers(data));
if (!skipDraw(data, mode))
......
......@@ -408,7 +408,7 @@ class Renderer9 : public RendererD3D
const void *indices,
GLsizei instances);
gl::Error applyShaders(const gl::ContextState &data, GLenum drawMode);
gl::Error applyShaders(const gl::Context *context, GLenum drawMode);
void generateCaps(gl::Caps *outCaps,
gl::TextureCapsMap *outTextureCaps,
......
......@@ -2643,14 +2643,6 @@ TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMissmatch)
// Tests the WebGL removal of undefined behavior when attachments aren't written to.
TEST_P(WebGLCompatibilityTest, DrawBuffers)
{
// TODO(cwallez) AMD incorrectly write black to the first render target when the HLSL pixel
// shader doesn't write anything to the ouput.
if (IsD3D11() && IsAMD())
{
std::cout << "Test skipped on AMD " << GetParam() << std::endl;
return;
}
// Make sure we can use at least 4 attachments for the tests.
bool useEXT = false;
if (getClientMajorVersion() < 3)
......
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