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