blob: ae7d96305a74250f653575039bad3dc8fd982c67 [file] [log] [blame]
// Copyright (c) 2013 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.
//
// Clear11.cpp: Framebuffer clear utility class.
#include "libANGLE/renderer/d3d/d3d11/Clear11.h"
#include <algorithm>
#include "libANGLE/Context.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "third_party/trace_event/trace_event.h"
// Precompiled shaders
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11_fl9vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewgs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewvs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/cleardepth11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps1.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps2.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps3.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps4.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps5.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps6.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps7.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps8.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps1.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps2.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps3.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps4.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps5.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps6.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps7.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps8.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps1.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps2.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps3.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps4.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps5.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps6.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps7.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps8.h"
namespace rx
{
namespace
{
constexpr uint32_t g_ConstantBufferSize = sizeof(RtvDsvClearInfo<float>);
constexpr uint32_t g_VertexSize = sizeof(d3d11::PositionVertex);
// Updates color, depth and alpha components of cached CB if necessary.
// Returns true if any constants are updated, false otherwise.
template <typename T>
bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
const gl::Color<T> &color,
const float *zValue,
const uint32_t numRtvs,
const uint8_t writeMask)
{
bool cacheDirty = false;
if (numRtvs > 0)
{
const bool writeRGB = (writeMask & ~D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0;
if (writeRGB && memcmp(&dataCache->r, &color.red, sizeof(T) * 3) != 0)
{
dataCache->r = color.red;
dataCache->g = color.green;
dataCache->b = color.blue;
cacheDirty = true;
}
const bool writeAlpha = (writeMask & D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0;
if (writeAlpha && (dataCache->a != color.alpha))
{
dataCache->a = color.alpha;
cacheDirty = true;
}
}
if (zValue)
{
const float clampedZValue = gl::clamp01(*zValue);
if (clampedZValue != dataCache->z)
{
dataCache->z = clampedZValue;
cacheDirty = true;
}
}
return cacheDirty;
}
bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
{
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
const auto &offset = viewportOffsets[i];
if (offset.x < 0 || offset.y < 0)
{
return false;
}
}
return true;
}
} // anonymous namespace
#define CLEARPS(Index) \
d3d11::LazyShader<ID3D11PixelShader>(g_PS_Clear##Index, ArraySize(g_PS_Clear##Index), \
"Clear11 PS " ANGLE_STRINGIFY(Index))
Clear11::ShaderManager::ShaderManager()
: mIl9(),
mVs9(g_VS_Clear_FL9, ArraySize(g_VS_Clear_FL9), "Clear11 VS FL9"),
mPsFloat9(g_PS_ClearFloat_FL9, ArraySize(g_PS_ClearFloat_FL9), "Clear11 PS FloatFL9"),
mVs(g_VS_Clear, ArraySize(g_VS_Clear), "Clear11 VS"),
mVsMultiview(g_VS_Multiview_Clear, ArraySize(g_VS_Multiview_Clear), "Clear11 VS Multiview"),
mGsMultiview(g_GS_Multiview_Clear, ArraySize(g_GS_Multiview_Clear), "Clear11 GS Multiview"),
mPsDepth(g_PS_ClearDepth, ArraySize(g_PS_ClearDepth), "Clear11 PS Depth"),
mPsFloat{{CLEARPS(Float1), CLEARPS(Float2), CLEARPS(Float3), CLEARPS(Float4), CLEARPS(Float5),
CLEARPS(Float6), CLEARPS(Float7), CLEARPS(Float8)}},
mPsUInt{{CLEARPS(Uint1), CLEARPS(Uint2), CLEARPS(Uint3), CLEARPS(Uint4), CLEARPS(Uint5),
CLEARPS(Uint6), CLEARPS(Uint7), CLEARPS(Uint8)}},
mPsSInt{{CLEARPS(Sint1), CLEARPS(Sint2), CLEARPS(Sint3), CLEARPS(Sint4), CLEARPS(Sint5),
CLEARPS(Sint6), CLEARPS(Sint7), CLEARPS(Sint8)}}
{}
#undef CLEARPS
Clear11::ShaderManager::~ShaderManager() {}
angle::Result Clear11::ShaderManager::getShadersAndLayout(const gl::Context *context,
Renderer11 *renderer,
const INT clearType,
const uint32_t numRTs,
const bool hasLayeredLayout,
const d3d11::InputLayout **il,
const d3d11::VertexShader **vs,
const d3d11::GeometryShader **gs,
const d3d11::PixelShader **ps)
{
Context11 *context11 = GetImplAs<Context11>(context);
if (renderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
ASSERT(clearType == GL_FLOAT);
ANGLE_TRY(mVs9.resolve(context11, renderer));
ANGLE_TRY(mPsFloat9.resolve(context11, renderer));
if (!mIl9.valid())
{
const D3D11_INPUT_ELEMENT_DESC ilDesc[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
InputElementArray ilDescArray(ilDesc);
ShaderData vertexShader(g_VS_Clear_FL9);
ANGLE_TRY(renderer->allocateResource(context11, ilDescArray, &vertexShader, &mIl9));
}
*vs = &mVs9.getObj();
*gs = nullptr;
*il = &mIl9;
*ps = &mPsFloat9.getObj();
return angle::Result::Continue;
}
if (!hasLayeredLayout)
{
ANGLE_TRY(mVs.resolve(context11, renderer));
*vs = &mVs.getObj();
*gs = nullptr;
}
else
{
// For layered framebuffers we have to use the multi-view versions of the VS and GS.
ANGLE_TRY(mVsMultiview.resolve(context11, renderer));
ANGLE_TRY(mGsMultiview.resolve(context11, renderer));
*vs = &mVsMultiview.getObj();
*gs = &mGsMultiview.getObj();
}
*il = nullptr;
if (numRTs == 0)
{
ANGLE_TRY(mPsDepth.resolve(context11, renderer));
*ps = &mPsDepth.getObj();
return angle::Result::Continue;
}
switch (clearType)
{
case GL_FLOAT:
ANGLE_TRY(mPsFloat[numRTs - 1].resolve(context11, renderer));
*ps = &mPsFloat[numRTs - 1].getObj();
break;
case GL_UNSIGNED_INT:
ANGLE_TRY(mPsUInt[numRTs - 1].resolve(context11, renderer));
*ps = &mPsUInt[numRTs - 1].getObj();
break;
case GL_INT:
ANGLE_TRY(mPsSInt[numRTs - 1].resolve(context11, renderer));
*ps = &mPsSInt[numRTs - 1].getObj();
break;
default:
UNREACHABLE();
break;
}
return angle::Result::Continue;
}
Clear11::Clear11(Renderer11 *renderer)
: mRenderer(renderer),
mResourcesInitialized(false),
mScissorEnabledRasterizerState(),
mScissorDisabledRasterizerState(),
mShaderManager(),
mConstantBuffer(),
mVertexBuffer(),
mShaderData({})
{}
Clear11::~Clear11() {}
angle::Result Clear11::ensureResourcesInitialized(const gl::Context *context)
{
if (mResourcesInitialized)
{
return angle::Result::Continue;
}
TRACE_EVENT0("gpu.angle", "Clear11::ensureResourcesInitialized");
static_assert((sizeof(RtvDsvClearInfo<float>) == sizeof(RtvDsvClearInfo<int>)),
"Size of rx::RtvDsvClearInfo<float> is not equal to rx::RtvDsvClearInfo<int>");
static_assert(
(sizeof(RtvDsvClearInfo<float>) == sizeof(RtvDsvClearInfo<uint32_t>)),
"Size of rx::RtvDsvClearInfo<float> is not equal to rx::RtvDsvClearInfo<uint32_t>");
static_assert((sizeof(RtvDsvClearInfo<float>) % 16 == 0),
"The size of RtvDsvClearInfo<float> should be a multiple of 16bytes.");
// Create Rasterizer States
D3D11_RASTERIZER_DESC rsDesc;
rsDesc.FillMode = D3D11_FILL_SOLID;
rsDesc.CullMode = D3D11_CULL_NONE;
rsDesc.FrontCounterClockwise = FALSE;
rsDesc.DepthBias = 0;
rsDesc.DepthBiasClamp = 0.0f;
rsDesc.SlopeScaledDepthBias = 0.0f;
rsDesc.DepthClipEnable = TRUE;
rsDesc.ScissorEnable = FALSE;
rsDesc.MultisampleEnable = FALSE;
rsDesc.AntialiasedLineEnable = FALSE;
Context11 *context11 = GetImplAs<Context11>(context);
ANGLE_TRY(mRenderer->allocateResource(context11, rsDesc, &mScissorDisabledRasterizerState));
mScissorDisabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor disabled");
rsDesc.ScissorEnable = TRUE;
ANGLE_TRY(mRenderer->allocateResource(context11, rsDesc, &mScissorEnabledRasterizerState));
mScissorEnabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor enabled");
// Initialize Depthstencil state with defaults
mDepthStencilStateKey.depthTest = false;
mDepthStencilStateKey.depthMask = false;
mDepthStencilStateKey.depthFunc = GL_ALWAYS;
mDepthStencilStateKey.stencilWritemask = static_cast<GLuint>(-1);
mDepthStencilStateKey.stencilBackWritemask = static_cast<GLuint>(-1);
mDepthStencilStateKey.stencilBackMask = 0;
mDepthStencilStateKey.stencilTest = false;
mDepthStencilStateKey.stencilMask = 0;
mDepthStencilStateKey.stencilFail = GL_REPLACE;
mDepthStencilStateKey.stencilPassDepthFail = GL_REPLACE;
mDepthStencilStateKey.stencilPassDepthPass = GL_REPLACE;
mDepthStencilStateKey.stencilFunc = GL_ALWAYS;
mDepthStencilStateKey.stencilBackFail = GL_REPLACE;
mDepthStencilStateKey.stencilBackPassDepthFail = GL_REPLACE;
mDepthStencilStateKey.stencilBackPassDepthPass = GL_REPLACE;
mDepthStencilStateKey.stencilBackFunc = GL_ALWAYS;
// Initialize BlendStateKey with defaults
mBlendStateKey.blendState.blend = false;
mBlendStateKey.blendState.sourceBlendRGB = GL_ONE;
mBlendStateKey.blendState.sourceBlendAlpha = GL_ONE;
mBlendStateKey.blendState.destBlendRGB = GL_ZERO;
mBlendStateKey.blendState.destBlendAlpha = GL_ZERO;
mBlendStateKey.blendState.blendEquationRGB = GL_FUNC_ADD;
mBlendStateKey.blendState.blendEquationAlpha = GL_FUNC_ADD;
mBlendStateKey.blendState.sampleAlphaToCoverage = false;
mBlendStateKey.blendState.dither = true;
mResourcesInitialized = true;
return angle::Result::Continue;
}
bool Clear11::useVertexBuffer() const
{
return (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3);
}
angle::Result Clear11::ensureConstantBufferCreated(const gl::Context *context)
{
if (mConstantBuffer.valid())
{
return angle::Result::Continue;
}
// Create constant buffer for color & depth data
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = g_ConstantBufferSize;
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = &mShaderData;
initialData.SysMemPitch = g_ConstantBufferSize;
initialData.SysMemSlicePitch = g_ConstantBufferSize;
ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferDesc, &initialData,
&mConstantBuffer));
mConstantBuffer.setDebugName("Clear11 Constant Buffer");
return angle::Result::Continue;
}
angle::Result Clear11::ensureVertexBufferCreated(const gl::Context *context)
{
ASSERT(useVertexBuffer());
if (mVertexBuffer.valid())
{
return angle::Result::Continue;
}
// Create vertex buffer with vertices for a quad covering the entire surface
static_assert((sizeof(d3d11::PositionVertex) % 16) == 0,
"d3d11::PositionVertex should be a multiple of 16 bytes");
const d3d11::PositionVertex vbData[6] = {{-1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f},
{-1.0f, -1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 0.0f, 1.0f},
{1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}};
const UINT vbSize = sizeof(vbData);
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = vbSize;
bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = vbData;
initialData.SysMemPitch = vbSize;
initialData.SysMemSlicePitch = initialData.SysMemPitch;
ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferDesc, &initialData,
&mVertexBuffer));
mVertexBuffer.setDebugName("Clear11 Vertex Buffer");
return angle::Result::Continue;
}
angle::Result Clear11::clearFramebuffer(const gl::Context *context,
const ClearParameters &clearParams,
const gl::FramebufferState &fboData)
{
ANGLE_TRY(ensureResourcesInitialized(context));
// Iterate over the color buffers which require clearing and determine if they can be
// cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView.
// This requires:
// 1) The render target is being cleared to a float value (will be cast to integer when clearing
// integer render targets as expected but does not work the other way around)
// 2) The format of the render target has no color channels that are currently masked out.
// Clear the easy-to-clear buffers on the spot and accumulate the ones that require special
// work.
//
// If these conditions are met, and:
// - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView.
// - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available.
// Otherwise perform a shader based clear.
//
// Also determine if the DSV can be cleared withID3D11DeviceContext::ClearDepthStencilView by
// checking if the stencil write mask covers the entire stencil.
//
// To clear the remaining buffers, a shader based clear is performed:
// - The appropriate ShaderManagers (VS & PS) for the clearType is set
// - A CB containing the clear color and Z values is bound
// - An IL and VB are bound (for FL93 and below)
// - ScissorRect/Raststate/Viewport set as required
// - Blendstate set containing appropriate colorMasks
// - DepthStencilState set with appropriate parameters for a z or stencil clear if required
// - Color and/or Z buffers to be cleared are bound
// - Primitive covering entire clear area is drawn
gl::Extents framebufferSize;
const auto *depthStencilAttachment = fboData.getDepthOrStencilAttachment();
if (depthStencilAttachment != nullptr)
{
framebufferSize = depthStencilAttachment->getSize();
}
else
{
const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment();
ASSERT(colorAttachment);
framebufferSize = colorAttachment->getSize();
}
const bool isSideBySideFBO =
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
bool needScissoredClear = false;
std::vector<D3D11_RECT> scissorRects;
if (clearParams.scissorEnabled)
{
const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
ASSERT(viewportOffsets != nullptr);
ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
if (clearParams.scissor.x >= framebufferSize.width ||
clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
clearParams.scissor.height == 0)
{
// The check assumes that the viewport offsets are not negative as according to the
// ANGLE_multiview spec.
// Scissor rect is outside the renderbuffer or is an empty rect.
return angle::Result::Continue;
}
if (isSideBySideFBO)
{
// We always have to do a scissor clear for side-by-side framebuffers.
needScissoredClear = true;
}
else
{
// Because the viewport offsets can generate scissor rectangles within the framebuffer's
// bounds, we can do this check only for non-side-by-side framebuffers.
if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
clearParams.scissor.y + clearParams.scissor.height <= 0)
{
// Scissor rect is outside the renderbuffer.
return angle::Result::Continue;
}
needScissoredClear =
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
}
if (needScissoredClear)
{
// Apply viewport offsets to compute the final scissor rectangles. This is valid also
// for non-side-by-side framebuffers, because the default viewport offset is {0,0}.
const size_t numViews = viewportOffsets->size();
scissorRects.reserve(numViews);
for (size_t i = 0u; i < numViews; ++i)
{
const gl::Offset &offset = (*viewportOffsets)[i];
D3D11_RECT rect;
int x = clearParams.scissor.x + offset.x;
int y = clearParams.scissor.y + offset.y;
rect.left = x;
rect.right = x + clearParams.scissor.width;
rect.top = y;
rect.bottom = y + clearParams.scissor.height;
scissorRects.emplace_back(rect);
}
}
}
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
std::array<ID3D11RenderTargetView *, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> rtvs;
std::array<uint8_t, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> rtvMasks = {};
uint32_t numRtvs = 0;
const uint8_t colorMask =
gl_d3d11::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen,
clearParams.colorMaskBlue, clearParams.colorMaskAlpha);
const auto &colorAttachments = fboData.getColorAttachments();
for (auto colorAttachmentIndex : fboData.getEnabledDrawBuffers())
{
const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex];
if (!clearParams.clearColor[colorAttachmentIndex])
{
continue;
}
RenderTarget11 *renderTarget = nullptr;
ANGLE_TRY(attachment.getRenderTarget(context, &renderTarget));
const gl::InternalFormat &formatInfo = *attachment.getFormat().info;
if (clearParams.colorType == GL_FLOAT &&
!(formatInfo.componentType == GL_FLOAT ||
formatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
formatInfo.componentType == GL_SIGNED_NORMALIZED))
{
WARN() << "It is undefined behaviour to clear a render buffer which is not "
"normalized fixed point or floating-point to floating point values (color "
"attachment "
<< colorAttachmentIndex << " has internal format " << attachment.getFormat()
<< ").";
}
if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) &&
(formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) &&
(formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) &&
(formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha))
{
// Every channel either does not exist in the render target or is masked out
continue;
}
const auto &framebufferRTV = renderTarget->getRenderTargetView();
ASSERT(framebufferRTV.valid());
if ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) ||
clearParams.colorType != GL_FLOAT ||
(formatInfo.redBits > 0 && !clearParams.colorMaskRed) ||
(formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
(formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) ||
(formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
{
rtvs[numRtvs] = framebufferRTV.get();
rtvMasks[numRtvs] = gl_d3d11::GetColorMask(formatInfo) & colorMask;
numRtvs++;
}
else
{
// ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is
// possible
const auto &nativeFormat = renderTarget->getFormatSet().format();
// Check if the actual format has a channel that the internal format does not and
// set them to the default values
float clearValues[4] = {
((formatInfo.redBits == 0 && nativeFormat.redBits > 0) ? 0.0f
: clearParams.colorF.red),
((formatInfo.greenBits == 0 && nativeFormat.greenBits > 0)
? 0.0f
: clearParams.colorF.green),
((formatInfo.blueBits == 0 && nativeFormat.blueBits > 0) ? 0.0f
: clearParams.colorF.blue),
((formatInfo.alphaBits == 0 && nativeFormat.alphaBits > 0)
? 1.0f
: clearParams.colorF.alpha),
};
if (formatInfo.alphaBits == 1)
{
// Some drivers do not correctly handle calling Clear() on a format with 1-bit
// alpha. They can incorrectly round all non-zero values up to 1.0f. Note that
// WARP does not do this. We should handle the rounding for them instead.
clearValues[3] = (clearParams.colorF.alpha >= 0.5f) ? 1.0f : 0.0f;
}
if (needScissoredClear)
{
// We shouldn't reach here if deviceContext1 is unavailable.
ASSERT(deviceContext1);
// There must be at least one scissor rectangle.
ASSERT(!scissorRects.empty());
deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
static_cast<UINT>(scissorRects.size()));
if (mRenderer->getWorkarounds().callClearTwice)
{
deviceContext1->ClearView(framebufferRTV.get(), clearValues,
scissorRects.data(),
static_cast<UINT>(scissorRects.size()));
}
}
else
{
deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
if (mRenderer->getWorkarounds().callClearTwice)
{
deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
}
}
}
}
ID3D11DepthStencilView *dsv = nullptr;
if (clearParams.clearDepth || clearParams.clearStencil)
{
RenderTarget11 *depthStencilRenderTarget = nullptr;
ASSERT(depthStencilAttachment != nullptr);
ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget));
dsv = depthStencilRenderTarget->getDepthStencilView().get();
ASSERT(dsv != nullptr);
const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format();
const auto *stencilAttachment = fboData.getStencilAttachment();
uint32_t stencilUnmasked =
(stencilAttachment != nullptr) ? (1 << nativeFormat.stencilBits) - 1 : 0;
bool needMaskedStencilClear =
clearParams.clearStencil &&
(clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
if (!needScissoredClear && !needMaskedStencilClear)
{
const UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) |
(clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0);
const FLOAT depthClear = gl::clamp01(clearParams.depthValue);
const UINT8 stencilClear = clearParams.stencilValue & 0xFF;
deviceContext->ClearDepthStencilView(dsv, clearFlags, depthClear, stencilClear);
dsv = nullptr;
}
}
if (numRtvs == 0 && dsv == nullptr)
{
return angle::Result::Continue;
}
// Clear the remaining render targets and depth stencil in one pass by rendering a quad:
//
// IA/VS: Vertices containing position and color members are passed through to the next stage.
// The vertex position has XY coordinates equal to clip extents and a Z component equal to the
// Z clear value. The vertex color contains the clear color.
//
// Rasterizer: Viewport scales the VS output over the entire surface and depending on whether
// or not scissoring is enabled the appropriate scissor rect and rasterizerState with or without
// the scissor test enabled is set as well.
//
// DepthStencilTest: DepthTesting, DepthWrites, StencilMask and StencilWrites will be enabled or
// disabled or set depending on what the input depthStencil clear parameters are. Since the PS
// is not writing out depth or rejecting pixels, this should happen prior to the PS stage.
//
// PS: Will write out the color values passed through from the previous stage to all outputs.
//
// OM: BlendState will perform the required color masking and output to RTV(s).
//
// ======================================================================================
//
// Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render-
// buffer that is not normalized fixed point or floating point with floating point values
// are undefined so we can just write floats to them and D3D11 will bit cast them to
// integers.
//
// Also, we don't have to worry about attempting to clear a normalized fixed/floating point
// buffer with integer values because there is no gl API call which would allow it,
// glClearBuffer* calls only clear a single renderbuffer at a time which is verified to
// be a compatible clear type.
ASSERT(numRtvs <= mRenderer->getNativeCaps().maxDrawBuffers);
// Setup BlendStateKey parameters
mBlendStateKey.blendState.colorMaskRed = clearParams.colorMaskRed;
mBlendStateKey.blendState.colorMaskGreen = clearParams.colorMaskGreen;
mBlendStateKey.blendState.colorMaskBlue = clearParams.colorMaskBlue;
mBlendStateKey.blendState.colorMaskAlpha = clearParams.colorMaskAlpha;
mBlendStateKey.rtvMax = numRtvs;
memcpy(mBlendStateKey.rtvMasks, &rtvMasks[0], sizeof(mBlendStateKey.rtvMasks));
// Get BlendState
const d3d11::BlendState *blendState = nullptr;
ANGLE_TRY(mRenderer->getBlendState(context, mBlendStateKey, &blendState));
const d3d11::DepthStencilState *dsState = nullptr;
const float *zValue = nullptr;
if (dsv)
{
// Setup DepthStencilStateKey
mDepthStencilStateKey.depthTest = clearParams.clearDepth;
mDepthStencilStateKey.depthMask = clearParams.clearDepth;
mDepthStencilStateKey.stencilWritemask = clearParams.stencilWriteMask;
mDepthStencilStateKey.stencilTest = clearParams.clearStencil;
// Get DepthStencilState
ANGLE_TRY(mRenderer->getDepthStencilState(context, mDepthStencilStateKey, &dsState));
zValue = clearParams.clearDepth ? &clearParams.depthValue : nullptr;
}
bool dirtyCb = false;
// Compare the input color/z values against the CB cache and update it if necessary
switch (clearParams.colorType)
{
case GL_FLOAT:
dirtyCb = UpdateDataCache(&mShaderData, clearParams.colorF, zValue, numRtvs, colorMask);
break;
case GL_UNSIGNED_INT:
dirtyCb = UpdateDataCache(reinterpret_cast<RtvDsvClearInfo<uint32_t> *>(&mShaderData),
clearParams.colorUI, zValue, numRtvs, colorMask);
break;
case GL_INT:
dirtyCb = UpdateDataCache(reinterpret_cast<RtvDsvClearInfo<int> *>(&mShaderData),
clearParams.colorI, zValue, numRtvs, colorMask);
break;
default:
UNREACHABLE();
break;
}
ANGLE_TRY(ensureConstantBufferCreated(context));
if (dirtyCb)
{
// Update the constant buffer with the updated cache contents
// TODO(Shahmeer): Consider using UpdateSubresource1 D3D11_COPY_DISCARD where possible.
D3D11_MAPPED_SUBRESOURCE mappedResource;
ANGLE_TRY(mRenderer->mapResource(context, mConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD,
0, &mappedResource));
memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize);
deviceContext->Unmap(mConstantBuffer.get(), 0);
}
auto *stateManager = mRenderer->getStateManager();
// Set the viewport to be the same size as the framebuffer.
stateManager->setSimpleViewport(framebufferSize);
// Apply state
stateManager->setSimpleBlendState(blendState);
const UINT stencilValue = clearParams.stencilValue & 0xFF;
stateManager->setDepthStencilState(dsState, stencilValue);
if (needScissoredClear)
{
stateManager->setRasterizerState(&mScissorEnabledRasterizerState);
}
else
{
stateManager->setRasterizerState(&mScissorDisabledRasterizerState);
}
// Get Shaders
const d3d11::VertexShader *vs = nullptr;
const d3d11::GeometryShader *gs = nullptr;
const d3d11::InputLayout *il = nullptr;
const d3d11::PixelShader *ps = nullptr;
const bool hasLayeredLayout =
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE);
ANGLE_TRY(mShaderManager.getShadersAndLayout(context, mRenderer, clearParams.colorType, numRtvs,
hasLayeredLayout, &il, &vs, &gs, &ps));
// Apply Shaders
stateManager->setDrawShaders(vs, gs, ps);
stateManager->setPixelConstantBuffer(0, &mConstantBuffer);
// Bind IL & VB if needed
stateManager->setIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
stateManager->setInputLayout(il);
if (useVertexBuffer())
{
ANGLE_TRY(ensureVertexBufferCreated(context));
stateManager->setSingleVertexBuffer(&mVertexBuffer, g_VertexSize, 0);
}
else
{
stateManager->setSingleVertexBuffer(nullptr, 0, 0);
}
stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Apply render targets
stateManager->setRenderTargets(&rtvs[0], numRtvs, dsv);
// If scissors are necessary to be applied, then the number of clears is the number of scissor
// rects. If no scissors are necessary, then a single full-size clear is enough.
size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u;
for (size_t i = 0u; i < necessaryNumClears; ++i)
{
if (needScissoredClear)
{
ASSERT(i < scissorRects.size());
stateManager->setScissorRectD3D(scissorRects[i]);
}
// Draw the fullscreen quad.
if (!hasLayeredLayout || isSideBySideFBO)
{
deviceContext->Draw(6, 0);
}
else
{
ASSERT(hasLayeredLayout);
deviceContext->DrawInstanced(6, static_cast<UINT>(fboData.getNumViews()), 0, 0);
}
}
return angle::Result::Continue;
}
} // namespace rx