summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp1152
1 files changed, 671 insertions, 481 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
index cd95c65d1c..f9dda0aeb4 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
@@ -1,4 +1,4 @@
-//
+
// 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.
@@ -20,624 +20,814 @@
#include "third_party/trace_event/trace_event.h"
// Precompiled shaders
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h"
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h"
+#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/clearuint11vs.h"
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h"
-
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11vs.h"
-#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.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>
-static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color<T> &color, float depth, void *buffer)
+bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
+ const gl::Color<T> &color,
+ const float *zValue,
+ const uint32_t numRtvs,
+ const uint8_t writeMask)
{
- d3d11::PositionDepthColorVertex<T> *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex<T>*>(buffer);
+ 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;
+ }
- float depthClear = gl::clamp01(depth);
- float left = -1.0f;
- float right = 1.0f;
- float top = -1.0f;
- float bottom = 1.0f;
+ const bool writeAlpha = (writeMask & D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0;
+ if (writeAlpha && (dataCache->a != color.alpha))
+ {
+ dataCache->a = color.alpha;
+ cacheDirty = true;
+ }
+ }
- // Clip the quad coordinates to the scissor if needed
- if (scissor != nullptr)
+ if (zValue)
{
- left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f);
- right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f);
- top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f);
- bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f);
+ const float clampedZValue = gl::clamp01(*zValue);
+
+ if (clampedZValue != dataCache->z)
+ {
+ dataCache->z = clampedZValue;
+ cacheDirty = true;
+ }
}
- d3d11::SetPositionDepthColorVertex<T>(vertices + 0, left, bottom, depthClear, color);
- d3d11::SetPositionDepthColorVertex<T>(vertices + 1, left, top, depthClear, color);
- d3d11::SetPositionDepthColorVertex<T>(vertices + 2, right, bottom, depthClear, color);
- d3d11::SetPositionDepthColorVertex<T>(vertices + 3, right, top, depthClear, color);
+ return cacheDirty;
}
-Clear11::ClearShader::ClearShader(DXGI_FORMAT colorType,
- const char *inputLayoutName,
- const BYTE *vsByteCode,
- size_t vsSize,
- const char *vsDebugName,
- const BYTE *psByteCode,
- size_t psSize,
- const char *psDebugName)
- : inputLayout(nullptr),
- vertexShader(vsByteCode, vsSize, vsDebugName),
- pixelShader(psByteCode, psSize, psDebugName)
+bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
{
- D3D11_INPUT_ELEMENT_DESC quadLayout[] =
+ for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
- { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- };
-
- inputLayout = new d3d11::LazyInputLayout(quadLayout, 2, vsByteCode, vsSize, inputLayoutName);
+ const auto &offset = viewportOffsets[i];
+ if (offset.x < 0 || offset.y < 0)
+ {
+ return false;
+ }
+ }
+ return true;
}
-
-Clear11::ClearShader::~ClearShader()
+} // 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)}}
{
- SafeDelete(inputLayout);
- vertexShader.release();
- pixelShader.release();
}
-Clear11::Clear11(Renderer11 *renderer)
- : mRenderer(renderer),
- mClearBlendStates(StructLessThan<ClearBlendInfo>),
- mFloatClearShader(nullptr),
- mUintClearShader(nullptr),
- mIntClearShader(nullptr),
- mClearDepthStencilStates(StructLessThan<ClearDepthStencilInfo>),
- mVertexBuffer(nullptr),
- mRasterizerState(nullptr)
+#undef CLEARPS
+
+Clear11::ShaderManager::~ShaderManager()
{
- TRACE_EVENT0("gpu.angle", "Clear11::Clear11");
+}
- HRESULT result;
- ID3D11Device *device = renderer->getDevice();
+gl::Error Clear11::ShaderManager::getShadersAndLayout(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)
+{
+ if (renderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ {
+ ASSERT(clearType == GL_FLOAT);
- D3D11_BUFFER_DESC vbDesc;
- vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex<float>) * 4;
- vbDesc.Usage = D3D11_USAGE_DYNAMIC;
- vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
- vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- vbDesc.MiscFlags = 0;
- vbDesc.StructureByteStride = 0;
+ ANGLE_TRY(mVs9.resolve(renderer));
+ ANGLE_TRY(mPsFloat9.resolve(renderer));
- result = device->CreateBuffer(&vbDesc, nullptr, &mVertexBuffer);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer");
+ if (!mIl9.valid())
+ {
+ const D3D11_INPUT_ELEMENT_DESC ilDesc[] = {
+ {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
- 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;
+ InputElementArray ilDescArray(ilDesc);
+ ShaderData vertexShader(g_VS_Clear_FL9);
- result = device->CreateRasterizerState(&rsDesc, &mRasterizerState);
- ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state");
+ ANGLE_TRY(renderer->allocateResource(ilDescArray, &vertexShader, &mIl9));
+ }
- if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
+ *vs = &mVs9.getObj();
+ *gs = nullptr;
+ *il = &mIl9;
+ *ps = &mPsFloat9.getObj();
+ return gl::NoError();
+ }
+ if (!hasLayeredLayout)
{
- mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT,
- "Clear11 Float IL",
- g_VS_ClearFloat,
- ArraySize(g_VS_ClearFloat),
- "Clear11 Float VS",
- g_PS_ClearFloat_FL9,
- ArraySize(g_PS_ClearFloat_FL9),
- "Clear11 Float PS");
+ ANGLE_TRY(mVs.resolve(renderer));
+ *vs = &mVs.getObj();
+ *gs = nullptr;
}
else
{
- mFloatClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_FLOAT,
- "Clear11 Float IL",
- g_VS_ClearFloat,
- ArraySize(g_VS_ClearFloat),
- "Clear11 Float VS",
- g_PS_ClearFloat,
- ArraySize(g_PS_ClearFloat),
- "Clear11 Float PS");
+ // For layered framebuffers we have to use the multi-view versions of the VS and GS.
+ ANGLE_TRY(mVsMultiview.resolve(renderer));
+ ANGLE_TRY(mGsMultiview.resolve(renderer));
+ *vs = &mVsMultiview.getObj();
+ *gs = &mGsMultiview.getObj();
+ }
+
+ *il = nullptr;
+
+ if (numRTs == 0)
+ {
+ ANGLE_TRY(mPsDepth.resolve(renderer));
+ *ps = &mPsDepth.getObj();
+ return gl::NoError();
}
- if (renderer->isES3Capable())
+ switch (clearType)
{
- mUintClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT,
- "Clear11 UINT IL",
- g_VS_ClearUint,
- ArraySize(g_VS_ClearUint),
- "Clear11 UINT VS",
- g_PS_ClearUint,
- ArraySize(g_PS_ClearUint),
- "Clear11 UINT PS");
- mIntClearShader = new ClearShader(DXGI_FORMAT_R32G32B32A32_UINT,
- "Clear11 SINT IL",
- g_VS_ClearSint,
- ArraySize(g_VS_ClearSint),
- "Clear11 SINT VS",
- g_PS_ClearSint,
- ArraySize(g_PS_ClearSint),
- "Clear11 SINT PS");
+ case GL_FLOAT:
+ ANGLE_TRY(mPsFloat[numRTs - 1].resolve(renderer));
+ *ps = &mPsFloat[numRTs - 1].getObj();
+ break;
+ case GL_UNSIGNED_INT:
+ ANGLE_TRY(mPsUInt[numRTs - 1].resolve(renderer));
+ *ps = &mPsUInt[numRTs - 1].getObj();
+ break;
+ case GL_INT:
+ ANGLE_TRY(mPsSInt[numRTs - 1].resolve(renderer));
+ *ps = &mPsSInt[numRTs - 1].getObj();
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
+
+ return gl::NoError();
+}
+
+Clear11::Clear11(Renderer11 *renderer)
+ : mRenderer(renderer),
+ mResourcesInitialized(false),
+ mScissorEnabledRasterizerState(),
+ mScissorDisabledRasterizerState(),
+ mShaderManager(),
+ mConstantBuffer(),
+ mVertexBuffer(),
+ mShaderData({})
+{
}
Clear11::~Clear11()
{
- for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++)
+}
+
+gl::Error Clear11::ensureResourcesInitialized()
+{
+ if (mResourcesInitialized)
{
- SafeRelease(i->second);
+ return gl::NoError();
}
- mClearBlendStates.clear();
- SafeDelete(mFloatClearShader);
- SafeDelete(mUintClearShader);
- SafeDelete(mIntClearShader);
+ 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>");
- for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++)
+ 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;
+
+ ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorDisabledRasterizerState));
+ mScissorDisabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor disabled");
+
+ rsDesc.ScissorEnable = TRUE;
+ ANGLE_TRY(mRenderer->allocateResource(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 gl::NoError();
+}
+
+bool Clear11::useVertexBuffer() const
+{
+ return (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3);
+}
+
+gl::Error Clear11::ensureConstantBufferCreated()
+{
+ if (mConstantBuffer.valid())
{
- SafeRelease(i->second);
+ return gl::NoError();
}
- mClearDepthStencilStates.clear();
- SafeRelease(mVertexBuffer);
- SafeRelease(mRasterizerState);
+ // 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(bufferDesc, &initialData, &mConstantBuffer));
+ mConstantBuffer.setDebugName("Clear11 Constant Buffer");
+ return gl::NoError();
}
-gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData)
+gl::Error Clear11::ensureVertexBufferCreated()
{
- const auto &colorAttachments = fboData.getColorAttachments();
- const auto &drawBufferStates = fboData.getDrawBufferStates();
- const auto *depthAttachment = fboData.getDepthAttachment();
- const auto *stencilAttachment = fboData.getStencilAttachment();
+ ASSERT(useVertexBuffer());
+
+ if (mVertexBuffer.valid())
+ {
+ return gl::NoError();
+ }
+
+ // 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(bufferDesc, &initialData, &mVertexBuffer));
+ mVertexBuffer.setDebugName("Clear11 Vertex Buffer");
+ return gl::NoError();
+}
- ASSERT(colorAttachments.size() == drawBufferStates.size());
+gl::Error Clear11::clearFramebuffer(const gl::Context *context,
+ const ClearParameters &clearParams,
+ const gl::FramebufferState &fboData)
+{
+ ANGLE_TRY(ensureResourcesInitialized());
// 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)
+ // 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.
+ // 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 draw a quad.
+ // Otherwise perform a shader based clear.
//
- // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView
- // by checking if the stencil write mask covers the entire stencil.
+ // 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, quads must be drawn containing an int, uint or float vertex color
- // attribute.
+ // 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 gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment();
- if (colorAttachment != nullptr)
- {
- framebufferSize = colorAttachment->getSize();
- }
- else if (depthAttachment != nullptr)
- {
- framebufferSize = depthAttachment->getSize();
- }
- else if (stencilAttachment != nullptr)
+ const auto *depthStencilAttachment = fboData.getDepthOrStencilAttachment();
+ if (depthStencilAttachment != nullptr)
{
- framebufferSize = stencilAttachment->getSize();
+ framebufferSize = depthStencilAttachment->getSize();
}
else
{
- UNREACHABLE();
- return gl::Error(GL_INVALID_OPERATION);
+ const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment();
+
+ if (!colorAttachment)
+ {
+ UNREACHABLE();
+ return gl::InternalError();
+ }
+
+ framebufferSize = colorAttachment->getSize();
}
- if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width ||
- clearParams.scissor.y >= framebufferSize.height ||
- clearParams.scissor.x + clearParams.scissor.width <= 0 ||
- clearParams.scissor.y + clearParams.scissor.height <= 0))
+ const bool isSideBySideFBO =
+ (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
+ bool needScissoredClear = false;
+ std::vector<D3D11_RECT> scissorRects;
+ if (clearParams.scissorEnabled)
{
- // Scissor is enabled and the scissor rectangle is outside the renderbuffer
- return gl::Error(GL_NO_ERROR);
- }
+ const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
+ ASSERT(viewportOffsets != nullptr);
+ ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
- bool needScissoredClear = clearParams.scissorEnabled && (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 (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 gl::NoError();
+ }
- std::vector<MaskedRenderTarget> maskedClearRenderTargets;
- RenderTarget11* maskedClearDepthStencil = nullptr;
+ 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 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();
-#if defined(ANGLE_ENABLE_D3D11_1)
+ 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();
-#endif
- ID3D11Device *device = mRenderer->getDevice();
- for (size_t colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachments.size();
- colorAttachmentIndex++)
+ 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] && attachment.isAttached() &&
- drawBufferStates[colorAttachmentIndex] != GL_NONE)
+ if (!clearParams.clearColor[colorAttachmentIndex])
{
- RenderTarget11 *renderTarget = nullptr;
- gl::Error error = attachment.getRenderTarget(&renderTarget);
- if (error.isError())
- {
- return error;
- }
+ continue;
+ }
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment.getInternalFormat());
+ RenderTarget11 *renderTarget = nullptr;
+ ANGLE_TRY(attachment.getRenderTarget(context, &renderTarget));
- if (clearParams.colorClearType == 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 %u has internal format "
- "0x%X).",
- colorAttachmentIndex, attachment.getInternalFormat());
- }
+ const gl::InternalFormat &formatInfo = *attachment.getFormat().info;
- 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;
- }
- else if ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) || clearParams.colorClearType != GL_FLOAT ||
- (formatInfo.redBits > 0 && !clearParams.colorMaskRed) ||
- (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) ||
- (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) ||
- (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha))
- {
- // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable
- MaskedRenderTarget maskAndRt;
- bool clearColor = clearParams.clearColor[colorAttachmentIndex];
- maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed);
- maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen);
- maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue);
- maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha);
- maskAndRt.renderTarget = renderTarget;
- maskedClearRenderTargets.push_back(maskAndRt);
- }
- else
- {
- // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible
+ 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()
+ << ").";
+ }
- ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView();
- if (!framebufferRTV)
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null.");
- }
+ 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::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat());
+ const auto &framebufferRTV = renderTarget->getRenderTargetView();
+ ASSERT(framebufferRTV.valid());
- // 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 && dxgiFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red),
- ((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green),
- ((formatInfo.blueBits == 0 && dxgiFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue),
- ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha),
- };
+ 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 (dxgiFormatInfo.alphaBits == 1)
+ 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)
{
- // 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.colorFClearValue.alpha >= 0.5f) ? 1.0f : 0.0f;
+ deviceContext1->ClearView(framebufferRTV.get(), clearValues,
+ scissorRects.data(),
+ static_cast<UINT>(scissorRects.size()));
}
-
-#if defined(ANGLE_ENABLE_D3D11_1)
- 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, clearValues, &rect, 1);
- }
- else
-#endif
+ }
+ else
+ {
+ deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
+ if (mRenderer->getWorkarounds().callClearTwice)
{
- deviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
+ deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues);
}
}
}
}
+ ID3D11DepthStencilView *dsv = nullptr;
+
if (clearParams.clearDepth || clearParams.clearStencil)
{
- const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment;
- ASSERT(attachment != nullptr);
+ RenderTarget11 *depthStencilRenderTarget = nullptr;
- RenderTarget11 *renderTarget = nullptr;
- gl::Error error = attachment->getRenderTarget(&renderTarget);
- if (error.isError())
- {
- return error;
- }
+ ASSERT(depthStencilAttachment != nullptr);
+ ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget));
- const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat());
+ dsv = depthStencilRenderTarget->getDepthStencilView().get();
+ ASSERT(dsv != nullptr);
- unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0;
- bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+ const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format();
+ const auto *stencilAttachment = fboData.getStencilAttachment();
- if (needScissoredClear || needMaskedStencilClear)
- {
- maskedClearDepthStencil = renderTarget;
- }
- else
+ uint32_t stencilUnmasked =
+ (stencilAttachment != nullptr) ? (1 << nativeFormat.stencilBits) - 1 : 0;
+ bool needMaskedStencilClear =
+ clearParams.clearStencil &&
+ (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+
+ if (!needScissoredClear && !needMaskedStencilClear)
{
- ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView();
- if (!framebufferDSV)
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null.");
- }
+ 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;
- UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) |
- (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0);
- FLOAT depthClear = gl::clamp01(clearParams.depthClearValue);
- UINT8 stencilClear = clearParams.stencilClearValue & 0xFF;
+ deviceContext->ClearDepthStencilView(dsv, clearFlags, depthClear, stencilClear);
- deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear);
+ dsv = nullptr;
}
}
- if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil)
+ if (numRtvs == 0 && dsv == nullptr)
{
- // To clear the render targets and depth stencil in one pass:
- //
- // Render a quad clipped to the scissor rectangle which draws the clear color and a blend
- // state that will perform the required color masking.
- //
- // The quad's depth is equal to the depth clear value with a depth stencil state that
- // will enable or disable depth test/writes if the depth buffer should be cleared or not.
- //
- // The rasterizer state's stencil is set to always pass or fail based on if the stencil
- // should be cleared or not with a stencil write mask of the stencil clear value.
- //
- // ======================================================================================
- //
- // 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.
-
- // Bind all the render targets which need clearing
- ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers);
- std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size());
- for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++)
- {
- RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget;
- ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView();
- if (!rtv)
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null.");
- }
+ return gl::NoError();
+ }
- rtvs[i] = rtv;
- }
- ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : nullptr;
+ // 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.
- ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets);
- const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
- const UINT sampleMask = 0xFFFFFFFF;
+ ASSERT(numRtvs <= mRenderer->getNativeCaps().maxDrawBuffers);
- ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams);
- const UINT stencilClear = clearParams.stencilClearValue & 0xFF;
+ // 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));
- // Set the vertices
- UINT vertexStride = 0;
- const UINT startIdx = 0;
- ClearShader *shader = nullptr;
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
- if (FAILED(result))
- {
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result);
- }
+ // Get BlendState
+ const d3d11::BlendState *blendState = nullptr;
+ ANGLE_TRY(mRenderer->getBlendState(mBlendStateKey, &blendState));
- const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : nullptr;
- switch (clearParams.colorClearType)
- {
- case GL_FLOAT:
- ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData);
- vertexStride = sizeof(d3d11::PositionDepthColorVertex<float>);
- shader = mFloatClearShader;
- break;
+ const d3d11::DepthStencilState *dsState = nullptr;
+ const float *zValue = nullptr;
- case GL_UNSIGNED_INT:
- ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData);
- vertexStride = sizeof(d3d11::PositionDepthColorVertex<unsigned int>);
- shader = mUintClearShader;
- break;
+ 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(mDepthStencilStateKey, &dsState));
+ zValue = clearParams.clearDepth ? &clearParams.depthValue : nullptr;
+ }
- case GL_INT:
- ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData);
- vertexStride = sizeof(d3d11::PositionDepthColorVertex<int>);
- shader = mIntClearShader;
- break;
+ bool dirtyCb = false;
- default:
+ // 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;
- }
-
- deviceContext->Unmap(mVertexBuffer, 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, blendFactors, sampleMask);
- deviceContext->OMSetDepthStencilState(dsState, stencilClear);
- deviceContext->RSSetState(mRasterizerState);
-
- // Apply shaders
- deviceContext->IASetInputLayout(shader->inputLayout->resolve(device));
- deviceContext->VSSetShader(shader->vertexShader.resolve(device), nullptr, 0);
- deviceContext->PSSetShader(shader->pixelShader.resolve(device), nullptr, 0);
- deviceContext->GSSetShader(nullptr, nullptr, 0);
-
- // Apply vertex buffer
- deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx);
- deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
-
- // Apply render targets
- deviceContext->OMSetRenderTargets(static_cast<unsigned int>(rtvs.size()),
- (rtvs.empty() ? nullptr : &rtvs[0]), dsv);
-
- // Draw the clear quad
- deviceContext->Draw(4, 0);
-
- // Clean up
- mRenderer->markAllStateDirty();
}
- return gl::Error(GL_NO_ERROR);
-}
+ ANGLE_TRY(ensureConstantBufferCreated());
-ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts)
-{
- ClearBlendInfo blendKey = {};
- for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ if (dirtyCb)
{
- if (i < rts.size())
- {
- RenderTarget11 *rt = rts[i].renderTarget;
- const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat());
-
- blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits > 0);
- blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0);
- blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits > 0);
- blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0);
- }
- else
+ // 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))
{
- blendKey.maskChannels[i][0] = false;
- blendKey.maskChannels[i][1] = false;
- blendKey.maskChannels[i][2] = false;
- blendKey.maskChannels[i][3] = false;
+ return gl::OutOfMemory() << "Clear11: Failed to map CB, " << gl::FmtHR(result);
}
- }
- ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey);
- if (i != mClearBlendStates.end())
- {
- return i->second;
+ memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize);
+ deviceContext->Unmap(mConstantBuffer.get(), 0);
}
- else
- {
- D3D11_BLEND_DESC blendDesc = { 0 };
- blendDesc.AlphaToCoverageEnable = FALSE;
- blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE;
- for (unsigned int j = 0; j < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; j++)
- {
- blendDesc.RenderTarget[j].BlendEnable = FALSE;
- blendDesc.RenderTarget[j].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[j][0],
- blendKey.maskChannels[j][1],
- blendKey.maskChannels[j][2],
- blendKey.maskChannels[j][3]);
- }
+ auto *stateManager = mRenderer->getStateManager();
- ID3D11Device *device = mRenderer->getDevice();
- ID3D11BlendState* blendState = nullptr;
- HRESULT result = device->CreateBlendState(&blendDesc, &blendState);
- if (FAILED(result) || !blendState)
- {
- ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
- return nullptr;
- }
+ // Set the viewport to be the same size as the framebuffer.
+ stateManager->setSimpleViewport(framebufferSize);
- mClearBlendStates[blendKey] = blendState;
+ // Apply state
+ stateManager->setSimpleBlendState(blendState);
- return blendState;
- }
-}
+ const UINT stencilValue = clearParams.stencilValue & 0xFF;
+ stateManager->setDepthStencilState(dsState, stencilValue);
-ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &clearParams)
-{
- ClearDepthStencilInfo dsKey = { 0 };
- dsKey.clearDepth = clearParams.clearDepth;
- dsKey.clearStencil = clearParams.clearStencil;
- dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF;
+ if (needScissoredClear)
+ {
+ stateManager->setRasterizerState(&mScissorEnabledRasterizerState);
+ }
+ else
+ {
+ stateManager->setRasterizerState(&mScissorDisabledRasterizerState);
+ }
- ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey);
- if (i != mClearDepthStencilStates.end())
+ // 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(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())
{
- return i->second;
+ ANGLE_TRY(ensureVertexBufferCreated());
+ stateManager->setSingleVertexBuffer(&mVertexBuffer, g_VertexSize, 0);
}
else
{
- D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 };
- dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE;
- dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
- dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
- dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE;
- dsDesc.StencilReadMask = 0;
- dsDesc.StencilWriteMask = dsKey.stencilWriteMask;
- dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
- dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
- dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
-
- ID3D11Device *device = mRenderer->getDevice();
- ID3D11DepthStencilState* dsState = nullptr;
- HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState);
- if (FAILED(result) || !dsState)
- {
- ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
- return nullptr;
- }
+ stateManager->setSingleVertexBuffer(nullptr, 0, 0);
+ }
- mClearDepthStencilStates[dsKey] = dsState;
+ stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- return dsState;
+ // 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 gl::NoError();
}
+
+} // namespace rx