blob: b2f44a7c5d83f0deb5d121f7a31c92e19a716bfd [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/FramebufferAttachment.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.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/clear11vs.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.h"
namespace rx
{
namespace
{
static constexpr uint32_t g_ConstantBufferSize = sizeof(RtvDsvClearInfo<float>);
static 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;
}
} // anonymous namespace
Clear11::ShaderManager::ShaderManager()
: mIl9(nullptr),
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"),
mPsFloat(g_PS_ClearFloat, ArraySize(g_PS_ClearFloat), "Clear11 PS Float"),
mPsUInt(g_PS_ClearUint, ArraySize(g_PS_ClearUint), "Clear11 PS UINT"),
mPsSInt(g_PS_ClearSint, ArraySize(g_PS_ClearSint), "Clear11 PS SINT")
{
}
Clear11::ShaderManager::~ShaderManager()
{
mVs9.release();
mPsFloat9.release();
mVs.release();
mPsFloat.release();
mPsUInt.release();
mPsSInt.release();
}
void Clear11::ShaderManager::getShadersAndLayout(ID3D11Device *device,
D3D_FEATURE_LEVEL featureLevel,
const INT clearType,
ID3D11InputLayout **il,
ID3D11VertexShader **vs,
ID3D11PixelShader **ps)
{
if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
ASSERT(clearType == GL_FLOAT);
*vs = mVs9.resolve(device);
if (mIl9.Get() == nullptr)
{
const D3D11_INPUT_ELEMENT_DESC ilDesc = {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0};
device->CreateInputLayout(&ilDesc, 1, g_VS_Clear_FL9, ArraySize(g_PS_ClearFloat_FL9),
mIl9.GetAddressOf());
}
*il = mIl9.Get();
*ps = mPsFloat9.resolve(device);
return;
}
*vs = mVs.resolve(device);
*il = nullptr;
switch (clearType)
{
case GL_FLOAT:
*ps = mPsFloat.resolve(device);
break;
case GL_UNSIGNED_INT:
*ps = mPsUInt.resolve(device);
break;
case GL_INT:
*ps = mPsSInt.resolve(device);
break;
default:
UNREACHABLE();
break;
}
}
Clear11::Clear11(Renderer11 *renderer)
: mRenderer(renderer),
mScissorEnabledRasterizerState(nullptr),
mScissorDisabledRasterizerState(nullptr),
mShaderManager(),
mConstantBuffer(nullptr),
mVertexBuffer(nullptr),
mShaderData({})
{
TRACE_EVENT0("gpu.angle", "Clear11::Clear11");
HRESULT result;
ID3D11Device *device = renderer->getDevice();
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 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;
result = device->CreateBuffer(&bufferDesc, &initialData, mConstantBuffer.GetAddressOf());
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mConstantBuffer, "Clear11 Constant Buffer");
const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel;
if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
// 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);
bufferDesc.ByteWidth = vbSize;
bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
initialData.pSysMem = vbData;
initialData.SysMemPitch = vbSize;
initialData.SysMemSlicePitch = initialData.SysMemPitch;
result = device->CreateBuffer(&bufferDesc, &initialData, mVertexBuffer.GetAddressOf());
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mVertexBuffer, "Clear11 Vertex Buffer");
}
// 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;
result = device->CreateRasterizerState(&rsDesc, mScissorDisabledRasterizerState.GetAddressOf());
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mScissorDisabledRasterizerState,
"Clear11 Rasterizer State with scissor disabled");
rsDesc.ScissorEnable = TRUE;
result = device->CreateRasterizerState(&rsDesc, mScissorEnabledRasterizerState.GetAddressOf());
ASSERT(SUCCEEDED(result));
d3d11::SetDebugName(mScissorEnabledRasterizerState,
"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 = static_cast<GLuint>(-1);
mDepthStencilStateKey.stencilTest = false;
mDepthStencilStateKey.stencilMask = static_cast<GLuint>(-1);
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;
mBlendStateKey.mrt = false;
memset(mBlendStateKey.rtvMasks, 0, sizeof(mBlendStateKey.rtvMasks));
}
Clear11::~Clear11()
{
}
gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams,
const gl::FramebufferState &fboData)
{
const auto &colorAttachments = fboData.getColorAttachments();
const auto &drawBufferStates = fboData.getDrawBufferStates();
const gl::FramebufferAttachment *depthStencilAttachment = fboData.getDepthOrStencilAttachment();
RenderTarget11 *depthStencilRenderTarget = nullptr;
ASSERT(colorAttachments.size() <= drawBufferStates.size());
if (clearParams.clearDepth || clearParams.clearStencil)
{
ASSERT(depthStencilAttachment != nullptr);
ANGLE_TRY(depthStencilAttachment->getRenderTarget(&depthStencilRenderTarget));
}
// 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;
if (depthStencilRenderTarget != nullptr)
{
framebufferSize = depthStencilRenderTarget->getExtents();
}
else
{
const auto colorAttachment = fboData.getFirstColorAttachment();
if (!colorAttachment)
{
UNREACHABLE();
return gl::InternalError();
}
framebufferSize = colorAttachment->getSize();
}
bool needScissoredClear = false;
if (clearParams.scissorEnabled)
{
if (clearParams.scissor.x >= framebufferSize.width ||
clearParams.scissor.y >= framebufferSize.height ||
clearParams.scissor.x + clearParams.scissor.width <= 0 ||
clearParams.scissor.y + clearParams.scissor.height <= 0 ||
clearParams.scissor.width == 0 || clearParams.scissor.height == 0)
{
// Scissor rect is outside the renderbuffer or is an empty rect
return gl::NoError();
}
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;
}
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;
ID3D11DepthStencilView *dsv = nullptr;
uint32_t numRtvs = 0;
const uint8_t colorMask =
gl_d3d11::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen,
clearParams.colorMaskBlue, clearParams.colorMaskAlpha);
for (size_t colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachments.size();
colorAttachmentIndex++)
{
const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex];
if (clearParams.clearColor[colorAttachmentIndex] && attachment.isAttached() &&
drawBufferStates[colorAttachmentIndex] != GL_NONE)
{
RenderTarget11 *renderTarget = nullptr;
ANGLE_TRY(attachment.getRenderTarget(&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))
{
ERR() << "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 d3d11::RenderTargetView &framebufferRTV = renderTarget->getRenderTargetView();
if (!framebufferRTV.valid())
{
return gl::OutOfMemory()
<< "Clear11: Render target view pointer unexpectedly null.";
}
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);
D3D11_RECT rect;
rect.left = clearParams.scissor.x;
rect.right = clearParams.scissor.x + clearParams.scissor.width;
rect.top = clearParams.scissor.y;
rect.bottom = clearParams.scissor.y + clearParams.scissor.height;
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget)
{
if (clearParams.scissor.width <= 16 || clearParams.scissor.height <= 16)
{
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
}
}
}
else
{
deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget)
{
if (framebufferSize.width <= 16 || framebufferSize.height <= 16)
{
deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
}
}
}
}
}
}
if (depthStencilRenderTarget)
{
dsv = depthStencilRenderTarget->getDepthStencilView();
if (!dsv)
{
return gl::OutOfMemory() << "Clear11: Depth stencil view pointer unexpectedly null.";
}
const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format();
const gl::FramebufferAttachment *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 gl::NoError();
}
// 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);
const UINT sampleMask = 0xFFFFFFFF;
ID3D11BlendState *blendState = nullptr;
if (numRtvs > 0)
{
// Setup BlendStateKey parameters
mBlendStateKey.blendState.colorMaskRed = clearParams.colorMaskRed;
mBlendStateKey.blendState.colorMaskGreen = clearParams.colorMaskGreen;
mBlendStateKey.blendState.colorMaskBlue = clearParams.colorMaskBlue;
mBlendStateKey.blendState.colorMaskAlpha = clearParams.colorMaskAlpha;
mBlendStateKey.mrt = numRtvs > 1;
memcpy(mBlendStateKey.rtvMasks, &rtvMasks[0], sizeof(mBlendStateKey.rtvMasks));
// Get BlendState
ANGLE_TRY(mRenderer->getStateCache().getBlendState(mBlendStateKey, &blendState));
}
const UINT stencilValue = clearParams.stencilValue & 0xFF;
ID3D11DepthStencilState *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->getStateCache().getDepthStencilState(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(reinterpret_cast<RtvDsvClearInfo<float> *>(&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;
}
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;
HRESULT result = deviceContext->Map(mConstantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0,
&mappedResource);
if (FAILED(result))
{
return gl::OutOfMemory() << "Clear11: Failed to map CB, " << result;
}
memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize);
deviceContext->Unmap(mConstantBuffer.Get(), 0);
}
// Set the viewport to be the same size as the framebuffer
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(framebufferSize.width);
viewport.Height = static_cast<FLOAT>(framebufferSize.height);
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
deviceContext->RSSetViewports(1, &viewport);
// Apply state
deviceContext->OMSetBlendState(blendState, nullptr, sampleMask);
deviceContext->OMSetDepthStencilState(dsState, stencilValue);
if (needScissoredClear)
{
const D3D11_RECT scissorRect = {clearParams.scissor.x, clearParams.scissor.y,
clearParams.scissor.x1(), clearParams.scissor.y1()};
deviceContext->RSSetScissorRects(1, &scissorRect);
deviceContext->RSSetState(mScissorEnabledRasterizerState.Get());
}
else
{
deviceContext->RSSetState(mScissorDisabledRasterizerState.Get());
}
// Get Shaders
const D3D_FEATURE_LEVEL fl = mRenderer->getRenderer11DeviceCaps().featureLevel;
ID3D11Device *device = mRenderer->getDevice();
ID3D11VertexShader *vs;
ID3D11InputLayout *il;
ID3D11PixelShader *ps;
mShaderManager.getShadersAndLayout(device, fl, clearParams.colorType, &il, &vs, &ps);
// Apply Shaders
deviceContext->VSSetShader(vs, nullptr, 0);
deviceContext->GSSetShader(nullptr, nullptr, 0);
deviceContext->PSSetShader(ps, nullptr, 0);
deviceContext->PSSetConstantBuffers(0, 1, mConstantBuffer.GetAddressOf());
// Bind IL & VB if needed
deviceContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
deviceContext->IASetInputLayout(il);
if (mVertexBuffer.Get())
{
const UINT offset = 0;
deviceContext->IASetVertexBuffers(0, 1, mVertexBuffer.GetAddressOf(), &g_VertexSize,
&offset);
}
else
{
deviceContext->IASetVertexBuffers(0, 0, nullptr, nullptr, nullptr);
}
deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Apply render targets
mRenderer->getStateManager()->setOneTimeRenderTargets(&rtvs[0], numRtvs, dsv);
// Draw the fullscreen quad
deviceContext->Draw(6, 0);
// Clean up
mRenderer->markAllStateDirty();
return gl::NoError();
}
}