1 //
2 // Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render
8 // state objects.
9
10 #include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h"
11
12 #include <float.h>
13
14 #include "common/debug.h"
15 #include "libANGLE/Framebuffer.h"
16 #include "libANGLE/FramebufferAttachment.h"
17 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
18 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
19 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
20
21 namespace rx
22 {
23 using namespace gl_d3d11;
24
RenderStateCache()25 RenderStateCache::RenderStateCache()
26 : mBlendStateCache(kMaxStates),
27 mRasterizerStateCache(kMaxStates),
28 mDepthStencilStateCache(kMaxStates),
29 mSamplerStateCache(kMaxStates)
30 {
31 }
32
~RenderStateCache()33 RenderStateCache::~RenderStateCache()
34 {
35 }
36
clear()37 void RenderStateCache::clear()
38 {
39 mBlendStateCache.Clear();
40 mRasterizerStateCache.Clear();
41 mDepthStencilStateCache.Clear();
42 mSamplerStateCache.Clear();
43 }
44
45 // static
GetBlendStateKey(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::BlendState & blendState)46 d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context,
47 const gl::Framebuffer *framebuffer,
48 const gl::BlendState &blendState)
49 {
50 d3d11::BlendStateKey key;
51 FramebufferD3D *framebufferD3D = GetImplAs<FramebufferD3D>(framebuffer);
52 const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(context);
53 const UINT8 blendStateMask =
54 gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
55 blendState.colorMaskBlue, blendState.colorMaskAlpha);
56
57 key.blendState = blendState;
58
59 for (size_t i = 0; i < colorbuffers.size(); i++)
60 {
61 const gl::FramebufferAttachment *attachment = colorbuffers[i];
62
63 if (attachment)
64 {
65 key.rtvMax = static_cast<uint32_t>(i) + 1;
66 key.rtvMasks[i] =
67 (gl_d3d11::GetColorMask(*attachment->getFormat().info)) & blendStateMask;
68 }
69 }
70
71 return key;
72 }
73
getBlendState(Renderer11 * renderer,const d3d11::BlendStateKey & key,const d3d11::BlendState ** outBlendState)74 gl::Error RenderStateCache::getBlendState(Renderer11 *renderer,
75 const d3d11::BlendStateKey &key,
76 const d3d11::BlendState **outBlendState)
77 {
78 auto keyIter = mBlendStateCache.Get(key);
79 if (keyIter != mBlendStateCache.end())
80 {
81 *outBlendState = &keyIter->second;
82 return gl::NoError();
83 }
84
85 TrimCache(kMaxStates, kGCLimit, "blend state", &mBlendStateCache);
86
87 // Create a new blend state and insert it into the cache
88 D3D11_BLEND_DESC blendDesc;
89 D3D11_RENDER_TARGET_BLEND_DESC &rtDesc0 = blendDesc.RenderTarget[0];
90 const gl::BlendState &blendState = key.blendState;
91
92 blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage;
93 blendDesc.IndependentBlendEnable = key.rtvMax > 1 ? TRUE : FALSE;
94
95 rtDesc0 = {};
96
97 if (blendState.blend)
98 {
99 rtDesc0.BlendEnable = true;
100 rtDesc0.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false);
101 rtDesc0.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false);
102 rtDesc0.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB);
103 rtDesc0.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true);
104 rtDesc0.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true);
105 rtDesc0.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha);
106 }
107
108 rtDesc0.RenderTargetWriteMask = key.rtvMasks[0];
109
110 for (unsigned int i = 1; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
111 {
112 blendDesc.RenderTarget[i] = rtDesc0;
113 blendDesc.RenderTarget[i].RenderTargetWriteMask = key.rtvMasks[i];
114 }
115
116 d3d11::BlendState d3dBlendState;
117 ANGLE_TRY(renderer->allocateResource(blendDesc, &d3dBlendState));
118 const auto &iter = mBlendStateCache.Put(key, std::move(d3dBlendState));
119
120 *outBlendState = &iter->second;
121
122 return gl::NoError();
123 }
124
getRasterizerState(Renderer11 * renderer,const gl::RasterizerState & rasterState,bool scissorEnabled,ID3D11RasterizerState ** outRasterizerState)125 gl::Error RenderStateCache::getRasterizerState(Renderer11 *renderer,
126 const gl::RasterizerState &rasterState,
127 bool scissorEnabled,
128 ID3D11RasterizerState **outRasterizerState)
129 {
130 d3d11::RasterizerStateKey key;
131 key.rasterizerState = rasterState;
132 key.scissorEnabled = scissorEnabled ? 1 : 0;
133
134 auto keyIter = mRasterizerStateCache.Get(key);
135 if (keyIter != mRasterizerStateCache.end())
136 {
137 *outRasterizerState = keyIter->second.get();
138 return gl::NoError();
139 }
140
141 TrimCache(kMaxStates, kGCLimit, "rasterizer state", &mRasterizerStateCache);
142
143 D3D11_CULL_MODE cullMode =
144 gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
145
146 // Disable culling if drawing points
147 if (rasterState.pointDrawMode)
148 {
149 cullMode = D3D11_CULL_NONE;
150 }
151
152 D3D11_RASTERIZER_DESC rasterDesc;
153 rasterDesc.FillMode = D3D11_FILL_SOLID;
154 rasterDesc.CullMode = cullMode;
155 rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE : TRUE;
156 rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of
157 // zero will preform no clamping, must be tested though.
158 rasterDesc.DepthClipEnable = TRUE;
159 rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE;
160 rasterDesc.MultisampleEnable = rasterState.multiSample;
161 rasterDesc.AntialiasedLineEnable = FALSE;
162
163 if (rasterState.polygonOffsetFill)
164 {
165 rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor;
166 rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits;
167 }
168 else
169 {
170 rasterDesc.SlopeScaledDepthBias = 0.0f;
171 rasterDesc.DepthBias = 0;
172 }
173
174 d3d11::RasterizerState dx11RasterizerState;
175 ANGLE_TRY(renderer->allocateResource(rasterDesc, &dx11RasterizerState));
176 *outRasterizerState = dx11RasterizerState.get();
177 mRasterizerStateCache.Put(key, std::move(dx11RasterizerState));
178
179 return gl::NoError();
180 }
181
getDepthStencilState(Renderer11 * renderer,const gl::DepthStencilState & glState,const d3d11::DepthStencilState ** outDSState)182 gl::Error RenderStateCache::getDepthStencilState(Renderer11 *renderer,
183 const gl::DepthStencilState &glState,
184 const d3d11::DepthStencilState **outDSState)
185 {
186 auto keyIter = mDepthStencilStateCache.Get(glState);
187 if (keyIter != mDepthStencilStateCache.end())
188 {
189 *outDSState = &keyIter->second;
190 return gl::NoError();
191 }
192
193 TrimCache(kMaxStates, kGCLimit, "depth stencil state", &mDepthStencilStateCache);
194
195 D3D11_DEPTH_STENCIL_DESC dsDesc = {0};
196 dsDesc.DepthEnable = glState.depthTest ? TRUE : FALSE;
197 dsDesc.DepthWriteMask = ConvertDepthMask(glState.depthMask);
198 dsDesc.DepthFunc = ConvertComparison(glState.depthFunc);
199 dsDesc.StencilEnable = glState.stencilTest ? TRUE : FALSE;
200 dsDesc.StencilReadMask = ConvertStencilMask(glState.stencilMask);
201 dsDesc.StencilWriteMask = ConvertStencilMask(glState.stencilWritemask);
202 dsDesc.FrontFace.StencilFailOp = ConvertStencilOp(glState.stencilFail);
203 dsDesc.FrontFace.StencilDepthFailOp = ConvertStencilOp(glState.stencilPassDepthFail);
204 dsDesc.FrontFace.StencilPassOp = ConvertStencilOp(glState.stencilPassDepthPass);
205 dsDesc.FrontFace.StencilFunc = ConvertComparison(glState.stencilFunc);
206 dsDesc.BackFace.StencilFailOp = ConvertStencilOp(glState.stencilBackFail);
207 dsDesc.BackFace.StencilDepthFailOp = ConvertStencilOp(glState.stencilBackPassDepthFail);
208 dsDesc.BackFace.StencilPassOp = ConvertStencilOp(glState.stencilBackPassDepthPass);
209 dsDesc.BackFace.StencilFunc = ConvertComparison(glState.stencilBackFunc);
210
211 d3d11::DepthStencilState dx11DepthStencilState;
212 ANGLE_TRY(renderer->allocateResource(dsDesc, &dx11DepthStencilState));
213 const auto &iter = mDepthStencilStateCache.Put(glState, std::move(dx11DepthStencilState));
214
215 *outDSState = &iter->second;
216
217 return gl::NoError();
218 }
219
getSamplerState(Renderer11 * renderer,const gl::SamplerState & samplerState,ID3D11SamplerState ** outSamplerState)220 gl::Error RenderStateCache::getSamplerState(Renderer11 *renderer,
221 const gl::SamplerState &samplerState,
222 ID3D11SamplerState **outSamplerState)
223 {
224 auto keyIter = mSamplerStateCache.Get(samplerState);
225 if (keyIter != mSamplerStateCache.end())
226 {
227 *outSamplerState = keyIter->second.get();
228 return gl::NoError();
229 }
230
231 TrimCache(kMaxStates, kGCLimit, "sampler state", &mSamplerStateCache);
232
233 const auto &featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
234
235 D3D11_SAMPLER_DESC samplerDesc;
236 samplerDesc.Filter =
237 gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter,
238 samplerState.maxAnisotropy, samplerState.compareMode);
239 samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS);
240 samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
241 samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR);
242 samplerDesc.MipLODBias = 0;
243 samplerDesc.MaxAnisotropy =
244 gl_d3d11::ConvertMaxAnisotropy(samplerState.maxAnisotropy, featureLevel);
245 samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc);
246 samplerDesc.BorderColor[0] = 0.0f;
247 samplerDesc.BorderColor[1] = 0.0f;
248 samplerDesc.BorderColor[2] = 0.0f;
249 samplerDesc.BorderColor[3] = 0.0f;
250 samplerDesc.MinLOD = samplerState.minLod;
251 samplerDesc.MaxLOD = samplerState.maxLod;
252
253 if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
254 {
255 // Check that maxLOD is nearly FLT_MAX (1000.0f is the default), since 9_3 doesn't support
256 // anything other than FLT_MAX. Note that Feature Level 9_* only supports GL ES 2.0, so the
257 // consumer of ANGLE can't modify the Max LOD themselves.
258 ASSERT(samplerState.maxLod >= 999.9f);
259
260 // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD
261 // workaround) should take account of this.
262 samplerDesc.MaxLOD = FLT_MAX;
263 }
264
265 d3d11::SamplerState dx11SamplerState;
266 ANGLE_TRY(renderer->allocateResource(samplerDesc, &dx11SamplerState));
267 *outSamplerState = dx11SamplerState.get();
268 mSamplerStateCache.Put(samplerState, std::move(dx11SamplerState));
269
270 return gl::NoError();
271 }
272
273 } // namespace rx
274